Updated radeon driver to the latest BeBits release 5.1.0.1.

Probably only works under Haiku due to the new area flags.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12219 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-04-01 14:16:38 +00:00
parent eb2068515f
commit e02e12de8a
46 changed files with 3357 additions and 1550 deletions
@@ -15,8 +15,6 @@
// additional timing flags for GetMode/SetMode
enum {
RADEON_MODE_STANDARD = 0 << 16,
RADEON_MODE_MIRROR = 1 << 16,
RADEON_MODE_CLONE = 2 << 16,
RADEON_MODE_COMBINE = 3 << 16,
RADEON_MODE_MASK = 7 << 16,
@@ -32,8 +30,9 @@ enum {
// operation codes tunneled via ProposeDisplayMode
typedef enum {
ms_swap,
ms_overlay_port
ms_swap = 'sw',
ms_use_laptop_panel = 'up',
ms_tv_standard = 'tv'
} multi_mon_settings;
@@ -137,27 +137,4 @@
#define RADEON_CUR2_OFFSET 0x0360
# define RADEON_CUR2_LOCK (1 << 31)
#define RADEON_GRPH_BUFFER_CNTL 0x02f0
# define RADEON_GRPH_START_REQ_MASK (0x7f)
# define RADEON_GRPH_START_REQ_SHIFT 0
# define RADEON_GRPH_STOP_REQ_MASK (0x7f<<8)
# define RADEON_GRPH_STOP_REQ_SHIFT 8
# define RADEON_GRPH_CRITICAL_POINT_MASK (0x7f<<16)
# define RADEON_GRPH_CRITICAL_POINT_SHIFT 16
# define RADEON_GRPH_CRITICAL_CNTL (1<<28)
# define RADEON_GRPH_BUFFER_SIZE (1<<29)
# define RADEON_GRPH_CRITICAL_AT_SOF (1<<30)
# define RADEON_GRPH_STOP_CNTL (1<<31)
#define RADEON_GRPH2_BUFFER_CNTL 0x03f0
# define RADEON_GRPH2_START_REQ_MASK (0x7f)
# define RADEON_GRPH2_START_REQ_SHIFT 0
# define RADEON_GRPH2_STOP_REQ_MASK (0x7f<<8)
# define RADEON_GRPH2_STOP_REQ_SHIFT 8
# define RADEON_GRPH2_CRITICAL_POINT_MASK (0x7f<<16)
# define RADEON_GRPH2_CRITICAL_POINT_SHIFT 16
# define RADEON_GRPH2_CRITICAL_CNTL (1<<28)
# define RADEON_GRPH2_BUFFER_SIZE (1<<29)
# define RADEON_GRPH2_CRITICAL_AT_SOF (1<<30)
# define RADEON_GRPH2_STOP_CNTL (1<<31)
#endif
+35 -6
View File
@@ -17,6 +17,7 @@
# define RADEON_DAC_CMP_EN (1 << 3)
# define RADEON_DAC_CMP_OUTPUT (1 << 7)
# define RADEON_DAC_8BIT_EN (1 << 8)
# define RADEON_DAC_TVO_EN (1 << 10)
# define RADEON_DAC_VGA_ADR_EN (1 << 13)
# define RADEON_DAC_PDWN (1 << 15)
# define RADEON_DAC_MASK_ALL (0xff << 24)
@@ -57,12 +58,40 @@
#define RADEON_DAC_W_INDEX 0x03c8 /* VGA */
#define RADEON_DISP_OUTPUT_CNTL 0x0d64
# define RADEON_DISP_DAC_SOURCE_MASK 0x03
# define RADEON_DISP_DAC_SOURCE_CRTC1 0x00
# define RADEON_DISP_DAC_SOURCE_CRTC2 0x01
# define RADEON_DISP_DAC_SOURCE_RMX 0x02
# define RADEON_DISP_TVDAC_SOURCE_MASK 0x0c
# define RADEON_DISP_TVDAC_SOURCE_CRTC2 0x04
# define RADEON_DISP_DAC_SOURCE_MASK 3
# define RADEON_DISP_DAC_SOURCE_CRTC1 0
# define RADEON_DISP_DAC_SOURCE_CRTC2 1
# define RADEON_DISP_DAC_SOURCE_RMX 2
# define RADEON_DISP_TVDAC_SOURCE_MASK (3 << 2)
# define RADEON_DISP_TVDAC_SOURCE_CRTC2 (1 << 2)
# define RADEON_DISP_TV_SOURCE (1 << 16)
# define RADEON_DISP_TV_MODE_MASK (3 << 17)
# define RADEON_DISP_TV_MODE_888 (0 << 17)
# define RADEON_DISP_TV_MODE_565 (1 << 17)
# define RADEON_DISP_TV_YG_DITH_EN (1 << 19)
# define RADEON_DISP_TV_CBB_CRR_DITH_EN (1 << 20)
# define RADEON_DISP_TV_BIT_WIDTH (1 << 21)
# define RADEON_DISP_TV_SYNC_MODE_SHIFT 22
# define RADEON_DISP_TV_SYNC_MODE_MASK (3 << 22)
# define RADEON_DISP_TV_SYNC_COLOR_MASK (3 << 25)
#define RADEON_DISP_TV_OUT_CNTL 0x0d6c
# define RADEON_DISP_TV_OUT_YG_FILTER_MASK (3 << 0)
# define RADEON_DISP_TV_OUT_YG_SAMPLE (1 << 2)
# define RADEON_DISP_TV_OUT_CrR_FILTER_MASK (3 << 4)
# define RADEON_DISP_TV_OUT_CrR_SAMPLE (1 << 6)
# define RADEON_DISP_TV_OUT_CbB_FILTER_MASK (3 << 8)
# define RADEON_DISP_TV_OUT_CbB_SAMPLE (1 << 10)
# define RADEON_DISP_TV_SUBSAMPLE_CNTL_MASK (3 << 12)
# define RADEON_DISP_TV_H_DOWNSCALE (1 << 15)
# define RADEON_DISP_TV_PATH_SRC (1 << 16)
# define RADEON_DISP_TV_COLOR_SPACE (1 << 17)
# define RADEON_DISP_TV_DITH_MODE (1 << 18)
# define RADEON_DISP_TV_DATA_ZERO_SEL (1 << 19)
# define RADEON_DISP_TV_CLKO_SEL (1 << 20)
# define RADEON_DISP_TV_CLKO_OUT_EN (1 << 21)
# define RADEON_DISP_TV_DOWNSCALE_CNTL (3 << 24)
#define RADEON_DISP_HW_DEBUG 0x0d14
# define RADEON_CRT2_DISP1_SEL (1 << 5)
@@ -25,4 +25,27 @@
#define RADEON_CRTC2_DISPLAY_BASE_ADDRESS 0x033c
#define RADEON_OV0_BASE_ADDRESS 0x043c
#define RADEON_GRPH_BUFFER_CNTL 0x02f0
# define RADEON_GRPH_START_REQ_MASK (0x7f)
# define RADEON_GRPH_START_REQ_SHIFT 0
# define RADEON_GRPH_STOP_REQ_MASK (0x7f<<8)
# define RADEON_GRPH_STOP_REQ_SHIFT 8
# define RADEON_GRPH_CRITICAL_POINT_MASK (0x7f<<16)
# define RADEON_GRPH_CRITICAL_POINT_SHIFT 16
# define RADEON_GRPH_CRITICAL_CNTL (1<<28)
# define RADEON_GRPH_BUFFER_SIZE (1<<29)
# define RADEON_GRPH_CRITICAL_AT_SOF (1<<30)
# define RADEON_GRPH_STOP_CNTL (1<<31)
#define RADEON_GRPH2_BUFFER_CNTL 0x03f0
# define RADEON_GRPH2_START_REQ_MASK (0x7f)
# define RADEON_GRPH2_START_REQ_SHIFT 0
# define RADEON_GRPH2_STOP_REQ_MASK (0x7f<<8)
# define RADEON_GRPH2_STOP_REQ_SHIFT 8
# define RADEON_GRPH2_CRITICAL_POINT_MASK (0x7f<<16)
# define RADEON_GRPH2_CRITICAL_POINT_SHIFT 16
# define RADEON_GRPH2_CRITICAL_CNTL (1<<28)
# define RADEON_GRPH2_BUFFER_SIZE (1<<29)
# define RADEON_GRPH2_CRITICAL_AT_SOF (1<<30)
# define RADEON_GRPH2_STOP_CNTL (1<<31)
#endif
@@ -14,6 +14,14 @@ class BScreen;
status_t GetSwapDisplays( BScreen *screen, bool *swap );
status_t SetSwapDisplays( BScreen *screen, bool swap );
status_t GetUseLaptopPanel( BScreen *screen, bool *use );
status_t SetUseLaptopPanel( BScreen *screen, bool use );
status_t GetNthSupportedTVStandard( BScreen *screen, int idx, uint32 *standard );
status_t GetTVStandard( BScreen *screen, uint32 *standard );
status_t SetTVStandard( BScreen *screen, uint32 standard );
status_t TestMultiMonSupport( BScreen *screen );
#endif
+4 -2
View File
@@ -47,12 +47,14 @@
# define RADEON_VCLK_SRC_PSCAN_CLK (1 << 0)
# define RADEON_VCLK_SRC_BYTE_CLK (2 << 0)
# define RADEON_VCLK_SRC_PPLL_CLK (3 << 0)
# define RADEON_PIXCLK_ALWAYS_ONb (1 << 6) // negated
# define RADEON_PIXCLK_DAC_ALWAYS_ONb (1 << 7) // negated
# define RADEON_ECP_DIV_SHIFT 8
# define RADEON_ECP_DIV_MASK (3 << 8)
# define RADEON_ECP_DIV_VCLK (0 << 8)
# define RADEON_ECP_DIV_VCLK_2 (1 << 8)
# define RADEON_PIXCLK_ALWAYS_ONb (1 << 6) // negated
# define RADEON_PIXCLK_DAC_ALWAYS_ONb (1 << 7) // negated
# define RADEON_VCLK_ECP_CNTL_BYTE_CLK_POST_DIV_SHIFT 16
# define RADEON_VCLK_ECP_CNTL_BYTE_CLK_POST_DIV_MASK (3 << 16)
#define RADEON_HTOTAL_CNTL 0x0009
#define RADEON_SCLK_CNTL 0x000d
# define RADEON_DYN_STOP_LAT_MASK 0x00007ff8
@@ -102,14 +102,16 @@ typedef enum {
rt_rs200, // IGP 330M/340M/350M
rt_r200, // Radeon 8500/9100
rt_rv250, // Radeon 9000
rt_rv280, // Radeon 9200
rt_m9, // mobile Radeon 9000
rt_rv280, // Radeon 9200
rt_m9plus, // mobile Radeon 9200
// from here on, r300 and up must be located as ATI modified the PLL
// with r300 and the code only tests for >= rt_r300
rt_r300, // Radeon 9700
rt_r300_4p, // Radeon 9500
rt_rv350, // Radeon 9600
rt_m10, // mobile Radeon 9600
rt_rv360, // Radeon 9600
rt_r350, // Radeon 9800
rt_r360 // Radeon 9800
@@ -118,13 +120,15 @@ typedef enum {
// TV standard
typedef enum {
ts_off,
ts_ntsc,
ts_pal,
ts_palm,
ts_palcn,
ts_pal_bdghi,
ts_pal_m,
ts_pal_nc,
ts_scart_pal,
ts_pal60
} tv_standard;
ts_pal_60,
ts_max = ts_pal_60
} tv_standard_e;
// type of TV-Chip
@@ -151,13 +155,6 @@ typedef struct {
} cursor_info;
// head as seen by accelerant
typedef struct {
int physical_head; // idx of physical head
uint32 rel_x, rel_y; // relative position in multi-monitor mode
} virtual_head;
// info about flat panel connected to LVDS or DVI port
typedef struct {
uint panel_pwr_delay;
@@ -175,16 +172,18 @@ typedef struct {
} fp_info;
// physical head
// crtc info
typedef struct {
bool is_crtc2; // true, if connected to crtc2
display_device_e active_displays; // currently driven displays
display_device_e chosen_displays; // displays to be driven by next mode switch
sem_id vblank; // vertical blank interrupt semaphore
bool cursor_on_screen; // cursor is visible on this head
display_mode mode; // display mode of this head
//bool is_crtc2; // true, if crtc2
int8 flatpanel_port; // linked flat panel port (-1 if none)
} physical_head;
bool cursor_on_screen; // cursor is visible on this head
int crtc_idx; // index of CRTC
display_device_e active_displays; // currently driven displays
display_device_e chosen_displays; // displays to be driven after next mode switch
sem_id vblank; // vertical blank interrupt semaphore
uint32 rel_x, rel_y; // relative position in multi-monitor mode
display_mode mode; // display mode of this head
} crtc_info;
// info about PLLs on graphics card as retrieved from BIOS
@@ -220,146 +219,6 @@ typedef struct {
} pll_info;
// PLL divider values
typedef struct {
uint32 post_code; // code for post divider
uint32 post; // value of post divider
uint32 extra_post_code; // code for extra post divider
uint32 extra_post; // value of extra post divider
uint32 ref; // reference divider
uint32 feedback; // feedback divider
uint32 freq; // resulting frequency
} pll_dividers;
// TV-Out parameters
typedef struct {
uint16 y_accum_init;
uint16 uv_accum_init;
uint16 uv_inc;
uint16 h_inc;
uint32 tv_clocks_to_active;
uint16 f_restart;
uint16 v_restart;
uint16 h_restart;
bool mode888;
uint16 y_saw_tooth_slope;
uint16 y_saw_tooth_amp;
uint16 y_rise_accum_init;
uint16 y_fall_accum_init;
bool y_coeff_enable;
uint8 y_coeff_value;
pll_dividers tv_dividers;
pll_dividers crt_dividers;
} tv_params;
// TV-timing
typedef struct {
uint32 freq; // TV sub carrier frequency x12
uint16 h_total;
uint16 h_sync_len;
uint16 h_genclk_delay;
uint16 h_setup_delay;
uint16 h_active_delay;
uint16 h_active_len;
uint16 v_total;
uint16 v_active_lines;
uint16 v_field_total;
uint16 v_fields;
uint16 f_total;
uint16 frame_size_adjust;
uint32 scale;
} tv_timing;
// list of register content (used for mode changes)
typedef struct {
// CRTC regs
uint32 crtc_h_total_disp;
uint32 crtc_h_sync_strt_wid;
uint32 crtc_v_total_disp;
uint32 crtc_v_sync_strt_wid;
uint32 crtc_pitch;
uint32 crtc_gen_cntl;
uint32 crtc_ext_cntl;
uint32 crtc_offset_cntl;
// RMX registers
uint32 fp_horz_stretch;
uint32 fp_vert_stretch;
// Flat panel regs
uint32 fp_gen_cntl;
uint32 fp_panel_cntl;
uint32 lvds_gen_cntl;
uint32 fp_h_sync_strt_wid;
uint32 fp_v_sync_strt_wid;
uint32 fp2_gen_cntl;
uint32 fp2_h_sync_strt_wid;
uint32 fp2_v_sync_strt_wid;
// DAC regs
uint32 dac_cntl2;
uint32 dac_cntl;
uint32 disp_hw_debug;
// PLL regs
uint32 ppll_div_3;
uint32 ppll_ref_div;
uint32 htotal_cntl;
// pure information
uint32 dot_clock_freq; // in 10 kHz
uint32 pll_output_freq;// in 10 kHz
int feedback_div;
int post_div;
// Common regs
uint32 surface_cntl;
uint32 disp_output_cntl;
// TV-Out registers
uint32 tv_ftotal;
uint32 tv_vscaler_cntl1;
uint32 tv_y_saw_tooth_cntl;
uint32 tv_y_fall_cntl;
uint32 tv_y_rise_cntl;
uint32 tv_vscaler_cntl2;
uint32 tv_hrestart;
uint32 tv_vrestart;
uint32 tv_frestart;
uint32 tv_tv_pll_cntl;
uint32 tv_crt_pll_cntl;
uint32 tv_clock_sel_cntl;
uint32 tv_clkout_cntl;
uint32 tv_htotal;
uint32 tv_hsize;
uint32 tv_hdisp;
uint32 tv_hstart;
uint32 tv_vtotal;
uint32 tv_vdisp;
uint32 tv_sync_size;
uint32 tv_timing_cntl;
uint32 tv_dac_cntl; // affects CRT connected to TV-DAC
uint32 tv_modulator_cntl1;
uint32 tv_modulator_cntl2;
uint32 tv_data_delay_a;
uint32 tv_data_delay_b;
uint32 tv_frame_lock_cntl;
uint32 tv_pll_cntl1;
uint32 tv_rgb_cntl;
uint32 tv_pre_dac_mux_cntl;
uint32 tv_master_cntl;
uint32 tv_uv_adr;
uint32 tv_pll_fine_cntl;
} port_regs;
// one overlay buffer
typedef struct overlay_buffer_node {
struct overlay_buffer_node *next, *prev;
@@ -382,7 +241,7 @@ typedef struct {
overlay_buffer_node *on; // current buffer
overlay_buffer_node *prev_on; // previous buffer (for temporal deinterlace, currently unused)
int8 head; // physical head where the overlay is shown on
int crtc_idx; // crtc where the overlay is shown on
uint32 rel_offset; // offset of overlay source due to clipping
} overlay_info;
@@ -393,8 +252,11 @@ typedef struct {
typedef struct {
uint32 id; // identifier used to know which card the 2D accelerator
// is prepared for (we use area_id of this structure)
virtual_head heads[2]; // heads assigned to virtual card
uint8 num_heads; // number of heads assigned to virtual card
bool assigned_crtc[2]; // mask of heads assigned to virtual card
bool used_crtc[2]; // mask of heads assigned to virtual card
display_device_e controlled_displays; // displays devices controlled byvc
display_device_e connected_displays; // bit-field of connected displays
int8 independant_heads; // number of heads to be programmed independantly
int8 different_heads; // number of heads showing different parts of framebuffer
@@ -410,9 +272,12 @@ typedef struct {
cursor_info cursor;
multi_mode_e wanted_multi_mode; // multi monitor mode as requested by user
bool swap_displays; // true to swap monitors
bool use_laptop_panel; // true to always use laptop panel
tv_standard_e tv_standard; // standard to use for TV Out
bool enforce_mode_change; // set to make sure next display mode change
// is executed even if display mode seems to be
// still the same
frame_buffer_config fbc; // data for direct frame buffer access
@@ -528,6 +393,7 @@ typedef struct {
radeon_type asic; // ASIC version
bool is_mobility; // mobility version
tv_chip_type tv_chip; // type of TV-Out encoder
bool new_pll; // r300 style PLL
uint8 theatre_channel; // VIP channel of Rage Theatre (if applicable)
@@ -539,11 +405,9 @@ typedef struct {
void *framebuffer_pci; // physical address of frame buffer (aka local memory)
// this is a hack needed by BeOS
physical_head heads[2]; // physical heads
uint8 num_heads; // number of physical heads
crtc_info crtc[2]; // info about each crtc
uint8 num_crtc; // number of physical heads
display_device_e connected_displays; // bit-field of connected displays
fp_info flatpanels[2]; // info about connected flat panels (if any)
memory_type_info memory[mt_last]; // info about memory types
@@ -618,6 +482,7 @@ typedef struct {
uint channel; // channel, i.e. device
uint address; // address
uint32 data; // read data
bool lock; // true, if CP lock must be acquired
} radeon_vip_read;
// write VIP register
@@ -626,6 +491,7 @@ typedef struct {
uint channel; // channel, i.e. device
uint address; // address
uint32 data; // data to write
bool lock; // true, if CP lock must be acquired
} radeon_vip_write;
// find channel of device with given ID
@@ -250,12 +250,10 @@
#define RADEON_TRAIL_X 0x1618
#define RADEON_TRAIL_X_SUB 0x1620
#define RADEON_VCLK_ECP_CNTL 0x0008 /* PLL */
#define RADEON_VGA_DDA_CONFIG 0x02e8
#define RADEON_VGA_DDA_CONFIG 0x02e8 // Rage 128 reg
#define RADEON_VGA_DDA_ON_OFF 0x02ec
#define RADEON_VID_BUFFER_CONTROL 0x0900
#define RADEON_VIDEOMUX_CNTL 0x0190
#define RADEON_VIPH_CONTROL 0x0c40 /* ? */
#define RADEON_OVR_CLR 0x0230
#define RADEON_OVR_WID_LEFT_RIGHT 0x0234
@@ -58,6 +58,9 @@
#define THEATRE_VIP_Y_FALL_CNTL 0x01cc
#define THEATRE_VIP_Y_RISE_CNTL 0x01d0
#define THEATRE_VIP_Y_SAW_TOOTH_CNTL 0x01d4
#define THEATRE_VIP_UPSAMP_AND_GAIN_CNTL 0x01e0
#define THEATRE_VIP_GAIN_LIMIT_SETTINGS 0x01e4
#define THEATRE_VIP_LINEAR_GAIN_SETTINGS 0x01e8
#define THEATRE_VIP_MODULATOR_CNTL1 0x0200
#define THEATRE_VIP_MODULATOR_CNTL2 0x0204
#define THEATRE_VIP_PRE_DAC_MUX_CNTL 0x0240
@@ -67,6 +70,21 @@
#define THEATRE_VIP_VBI_20BIT_CNTL 0x02d0
#define THEATRE_VIP_VBI_LEVEL_CNTL 0x02d8
#define THEATRE_VIP_UV_ADR 0x0300
#define THEATRE_VIP_UPSAMP_COEFF0_0 0x0340
#define THEATRE_VIP_UPSAMP_COEFF0_1 0x0344
#define THEATRE_VIP_UPSAMP_COEFF0_2 0x0348
#define THEATRE_VIP_UPSAMP_COEFF1_0 0x034c
#define THEATRE_VIP_UPSAMP_COEFF1_1 0x0350
#define THEATRE_VIP_UPSAMP_COEFF1_2 0x0354
#define THEATRE_VIP_UPSAMP_COEFF2_0 0x0358
#define THEATRE_VIP_UPSAMP_COEFF2_1 0x035c
#define THEATRE_VIP_UPSAMP_COEFF2_2 0x0360
#define THEATRE_VIP_UPSAMP_COEFF3_0 0x0364
#define THEATRE_VIP_UPSAMP_COEFF3_1 0x0368
#define THEATRE_VIP_UPSAMP_COEFF3_2 0x036c
#define THEATRE_VIP_UPSAMP_COEFF4_0 0x0370
#define THEATRE_VIP_UPSAMP_COEFF4_1 0x0374
#define THEATRE_VIP_UPSAMP_COEFF4_2 0x0378
#define THEATRE_VIP_HSCALER_CONTROL 0x0600
#define THEATRE_VIP_VSCALER_CONTROL 0x0604
+52 -4
View File
@@ -15,10 +15,13 @@
# define RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST (1 << 1)
# define RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX (1 << 3)
# define RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST (1 << 4)
# define RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST (1 << 5)
# define RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST (1 << 6)
# define RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST (1 << 7)
# define RADEON_TV_MASTER_CNTL_CRT_FIFO_CE_EN (1 << 9)
# define RADEON_TV_MASTER_CNTL_TV_FIFO_CE_EN (1 << 10)
# define RADEON_TV_MASTER_CNTL_RE_SYNC_NOW_SEL_MASK (3 << 14)
# define RADEON_TV_MASTER_CNTL_TV_CLK_ALWAYS_ONb (1 << 30)
# define RADEON_TV_MASTER_CNTL_TVCLK_ALWAYS_ONb (1 << 30)
# define RADEON_TV_MASTER_CNTL_TV_ON (1 << 31)
#define RADEON_TV_RGB_CNTL 0x0804
@@ -37,9 +40,24 @@
#define RADEON_TV_HRESTART 0x0838
#define RADEON_TV_VRESTART 0x083c
#define RADEON_TV_HOST_READ_DATA 0x0840
#define RADEON_TV_HOST_WRITE_DATA 0x0844
#define RADEON_TV_HOST_RD_WT_CNTL 0x0848
# define RADEON_TV_HOST_RD_WT_CNTL_RD (1 << 12)
# define RADEON_TV_HOST_RD_WT_CNTL_RD_ACK (1 << 13)
# define RADEON_TV_HOST_RD_WT_CNTL_WT (1 << 14)
# define RADEON_TV_HOST_RD_WT_CNTL_WT_ACK (1 << 15)
#define RADEON_TV_VSCALER_CNTL1 0x084c
# define RADEON_TV_VSCALER_CNTL1_RESTART_FIELD (1 << 29)
# define RADEON_TV_VSCALER_CNTL1_UV_INC_SHIFT 0
# define RADEON_TV_VSCALER_CNTL1_UV_INC_MASK 0x0000ffff
# define RADEON_TV_VSCALER_CNTL1_UV_THINNER_SHIFT 16
# define RADEON_TV_VSCALER_CNTL1_UV_THINNER_MASK 0x003f0000
# define RADEON_TV_VSCALER_CNTL1_Y_W_EN (1 << 24)
# define RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT 26
# define RADEON_TV_VSCALER_CNTL1_RESTART_FIELD (1 << 29)
#define RADEON_TV_TIMING_CNTL 0x0850
# define RADEON_TV_TIMING_CNTL_UV_OUTPUT_POST_SCALE_SHIFT 24
@@ -57,18 +75,26 @@
# define RADEON_TV_Y_FALL_CNTL_Y_COEFF_VALUE_SHIFT 24
#define RADEON_TV_Y_RISE_CNTL 0x085c
# define RADEON_TV_Y_RISE_CNTL_Y_RISE_PING_PONG 16
# define RADEON_TV_Y_RISE_CNTL_Y_RISE_PING_PONG (1 << 16)
#define RADEON_TV_Y_SAW_TOOTH_CNTL 0x0860
# define RADEON_TV_Y_SAW_TOOTH_CNTL_SLOPE_SHIFT 16
#define RADEON_TV_UPSAMP_AND_GAIN_CNTL 0x0864
#define RADEON_TV_GAIN_LIMIT_SETTINGS 0x0868
#define RADEON_TV_LINEAR_GAIN_SETTINGS 0x086c
#define RADEON_TV_MODULATOR_CNTL1 0x0870
# define RADEON_TV_MODULATOR_CNTL1_YFLT_EN (1 << 2)
# define RADEON_TV_MODULATOR_CNTL1_UVFLT_EN (1 << 3)
# define RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN (1 << 6)
# define RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL (1 << 7)
# define RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT 18
# define RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT 8
# define RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_MASK 0x00007f00
# define RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT 16
# define RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_MASK 0x007f0000
# define RADEON_TV_MODULATOR_CNTL1_SLEW_RATE_LIMIT (1 << 23)
# define RADEON_TV_MODULATOR_CNTL1_CY_FILT_BLEND_SHIFT 28
#define RADEON_TV_MODULATOR_CNTL2 0x0874
# define TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK 0x1ff
@@ -90,6 +116,7 @@
# define RADEON_TV_DAC_CNTL_NBLANK (1 << 0)
# define RADEON_TV_DAC_CNTL_NHOLD (1 << 1)
# define RADEON_TV_DAC_CNTL_PEDESTAL (1 << 2)
# define RADEON_TV_DAC_CNTL_DASLEEP (1 << 3) // Theatre only
# define RADEON_TV_DAC_CNTL_DETECT (1 << 4)
# define RADEON_TV_DAC_CNTL_CMPOUT (1 << 5)
# define RADEON_TV_DAC_CNTL_BGSLEEP (1 << 6)
@@ -99,11 +126,29 @@
# define RADEON_TV_DAC_CNTL_STD_RS343 (3 << 8)
# define RADEON_TV_DAC_CNTL_BGADJ_SHIFT 16
# define RADEON_TV_DAC_CNTL_DACADJ_SHIFT 20
# define RADEON_TV_DAC_CNTL_RDACPD (1 << 24)
# define RADEON_TV_DAC_CNTL_GDACPD (1 << 25)
# define RADEON_TV_DAC_CNTL_BDACPD (1 << 26)
# define RADEON_TV_DAC_CNTL_RDACDET (1 << 29)
# define RADEON_TV_DAC_CNTL_GDACDET (1 << 30)
# define RADEON_TV_DAC_CNTL_BDACDET (1 << 31)
#define RADEON_TV_CRC_CNTL 0x0890
#define RADEON_TV_UV_ADR 0x08ac
# define RADEON_TV_UV_ADR_MAX_UV_ADR_MASK 0x000000ff
# define RADEON_TV_UV_ADR_MAX_UV_ADR_SHIFT 0
# define RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK 0x0000ff00
# define RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT 8
# define RADEON_TV_UV_ADR_TABLE3_TOP_ADR_MASK 0x00ff0000
# define RADEON_TV_UV_ADR_TABLE3_TOP_ADR_SHIFT 16
# define RADEON_TV_UV_ADR_HCODE_TABLE_SEL_MASK 0x06000000
# define RADEON_TV_UV_ADR_HCODE_TABLE_SEL_SHIFT 25
# define RADEON_TV_UV_ADR_VCODE_TABLE_SEL_MASK 0x18000000
# define RADEON_TV_UV_ADR_VCODE_TABLE_SEL_SHIFT 27
#define RADEON_TV_MAX_FIFO_ADDR 0x1a7
#define RADEON_TV_MAX_FIFO_ADDR_INTERN 0x1ff
#define RADEON_TV_PLL_FINE_CNTL 0x20
@@ -138,4 +183,7 @@
# define RADEON_TV_PLL_CNTL1_TVPLL_TEST (1 << 31)
# define RADEON_TV_CLOCK_SEL_CNTL_BYTCLK_SHIFT 2
# define RADEON_TV_CLOCK_SEL_CNTL_BYTCLKD_SHIFT 8
#endif
+1 -1
View File
@@ -8,4 +8,4 @@
*/
// current version
#define RADEON_DRIVER_VERSION "Version: 4.1.0.0"
#define RADEON_DRIVER_VERSION "Version: 5.1.0.1"
+1 -1
View File
@@ -122,7 +122,7 @@ void Radeon_FreeIndirectBuffers( accelerator_info *ai )
// wait until an indirect buffer becomes available;
// lock must be hold
void Radeon_WaitForFreeIndirectBuffers( accelerator_info *ai )
static void Radeon_WaitForFreeIndirectBuffers( accelerator_info *ai )
{
bigtime_t start_time;
CP_info *cp = &ai->si->cp;
+51 -50
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
@@ -14,20 +14,19 @@
#include "mmio.h"
#include "crtc_regs.h"
static void doShowCursor( accelerator_info *ai, physical_head *head );
static void moveOneCursor( accelerator_info *ai, virtual_head *virtual_head, int x, int y );
static void moveOneCursor( accelerator_info *ai, int crtc_idx, int x, int y );
// set standard foreground/background colours
void Radeon_SetCursorColors( accelerator_info *ai, physical_head *head )
void Radeon_SetCursorColors( accelerator_info *ai, int crtc_idx )
{
SHOW_FLOW0( 3, "" );
if( head->is_crtc2 ) {
OUTREG( ai->regs, RADEON_CUR2_CLR0, 0xffffff );
OUTREG( ai->regs, RADEON_CUR2_CLR1, 0 );
} else {
if( crtc_idx == 0 ) {
OUTREG( ai->regs, RADEON_CUR_CLR0, 0xffffff );
OUTREG( ai->regs, RADEON_CUR_CLR1, 0 );
} else {
OUTREG( ai->regs, RADEON_CUR2_CLR0, 0xffffff );
OUTREG( ai->regs, RADEON_CUR2_CLR1, 0 );
}
}
@@ -115,9 +114,10 @@ void MOVE_CURSOR(uint16 x, uint16 y)
y -= vds;
// go
moveOneCursor( ai, &vc->heads[0], x, y );
if( vc->independant_heads > 1 )
moveOneCursor( ai, &vc->heads[1], x, y );
if( vc->used_crtc[0] )
moveOneCursor( ai, 0, x, y );
if( vc->used_crtc[1] )
moveOneCursor( ai, 1, x, y );
RELEASE_BEN( ai->si->engine.lock );
}
@@ -137,9 +137,10 @@ void SHOW_CURSOR( bool is_visible )
// the following functions take also care to not
// show the cursor if it's on the other port
doShowCursor( ai, &ai->si->heads[vc->heads[0].physical_head] );
if( vc->independant_heads > 1 )
doShowCursor( ai, &ai->si->heads[vc->heads[1].physical_head] );
if( vc->used_crtc[0] )
Radeon_ShowCursor( ai, 0 );
if( vc->used_crtc[1] )
Radeon_ShowCursor( ai, 1 );
RELEASE_BEN( ai->si->engine.lock );
}
@@ -147,38 +148,38 @@ void SHOW_CURSOR( bool is_visible )
// move cursor on one port
// main_port - common data is stored here
void moveOneCursor( accelerator_info *ai, virtual_head *virtual_head, int x, int y )
void moveOneCursor( accelerator_info *ai, int crtc_idx, int x, int y )
{
virtual_card *vc = ai->vc;
physical_head *head = &ai->si->heads[virtual_head->physical_head];
crtc_info *crtc = &ai->si->crtc[crtc_idx];
int xorigin, yorigin;
bool prev_state;
// adjust according to relative screen position
x -= virtual_head->rel_x;
y -= virtual_head->rel_y;
x -= crtc->rel_x;
y -= crtc->rel_y;
// and to hot spot
x -= vc->cursor.hot_x;
y -= vc->cursor.hot_y;
// check whether the cursor is (partially) visible on this screen
prev_state = head->cursor_on_screen;
head->cursor_on_screen = true;
prev_state = crtc->cursor_on_screen;
crtc->cursor_on_screen = true;
// in theory, cursor can be up to 64 pixels off screen,
// but there were display errors
if( y > head->mode.timing.v_display ||
x > head->mode.timing.h_display ||
if( y > crtc->mode.timing.v_display ||
x > crtc->mode.timing.h_display ||
x <= -16 || y <= -16 )
{
head->cursor_on_screen = false;
crtc->cursor_on_screen = false;
}
if( prev_state != head->cursor_on_screen )
doShowCursor( ai, head );
if( prev_state != crtc->cursor_on_screen )
Radeon_ShowCursor( ai, crtc_idx );
if( !head->cursor_on_screen )
if( !crtc->cursor_on_screen )
return;
// if upper-left corner of cursor is outside of
@@ -192,17 +193,7 @@ void moveOneCursor( accelerator_info *ai, virtual_head *virtual_head, int x, int
if( y < 0 )
yorigin = -y;
if( head->is_crtc2 ) {
OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_OFF, RADEON_CUR2_LOCK
| (xorigin << 16)
| yorigin );
OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_POSN, RADEON_CUR2_LOCK
| ((xorigin ? 0 : x) << 16)
| (yorigin ? 0 : y) );
OUTREG( ai->regs, RADEON_CUR2_OFFSET,
vc->cursor.fb_offset + xorigin + yorigin * 16 );
} else {
if( crtc_idx == 0 ) {
OUTREG( ai->regs, RADEON_CUR_HORZ_VERT_OFF, RADEON_CUR_LOCK
| (xorigin << 16)
| yorigin );
@@ -211,36 +202,46 @@ void moveOneCursor( accelerator_info *ai, virtual_head *virtual_head, int x, int
| (yorigin ? 0 : y) );
OUTREG( ai->regs, RADEON_CUR_OFFSET,
vc->cursor.fb_offset + xorigin + yorigin * 16 );
} else {
OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_OFF, RADEON_CUR2_LOCK
| (xorigin << 16)
| yorigin );
OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_POSN, RADEON_CUR2_LOCK
| ((xorigin ? 0 : x) << 16)
| (yorigin ? 0 : y) );
OUTREG( ai->regs, RADEON_CUR2_OFFSET,
vc->cursor.fb_offset + xorigin + yorigin * 16 );
}
}
// show cursor on one port, depending on official whishes and whether
// cursor is located on this subscreen
void doShowCursor( accelerator_info *ai, physical_head *head )
void Radeon_ShowCursor( accelerator_info *ai, int crtc_idx )
{
virtual_card *vc = ai->vc;
crtc_info *crtc = &ai->si->crtc[crtc_idx];
uint32 tmp;
if( head->is_crtc2 ) {
tmp = INREG( ai->regs, RADEON_CRTC2_GEN_CNTL );
if( vc->cursor.is_visible && head->cursor_on_screen )
tmp |= RADEON_CRTC2_CUR_EN;
else
tmp &= ~RADEON_CRTC2_CUR_EN;
OUTREG( ai->regs, RADEON_CRTC2_GEN_CNTL, tmp );
} else {
if( crtc_idx == 0 ) {
tmp = INREG( ai->regs, RADEON_CRTC_GEN_CNTL );
if( vc->cursor.is_visible && head->cursor_on_screen ) {
if( vc->cursor.is_visible && crtc->cursor_on_screen ) {
tmp |= RADEON_CRTC_CUR_EN;
} else {
tmp &= ~RADEON_CRTC_CUR_EN;
}
OUTREG( ai->regs, RADEON_CRTC_GEN_CNTL, tmp );
} else {
tmp = INREG( ai->regs, RADEON_CRTC2_GEN_CNTL );
if( vc->cursor.is_visible && crtc->cursor_on_screen )
tmp |= RADEON_CRTC2_CUR_EN;
else
tmp &= ~RADEON_CRTC2_CUR_EN;
OUTREG( ai->regs, RADEON_CRTC2_GEN_CNTL, tmp );
}
}
+7 -2
View File
@@ -80,10 +80,15 @@ sem_id ACCELERANT_RETRACE_SEMAPHORE(void)
// with multi-monitor mode, we have two vertical blanks!
// until we find a better solution, we always return virtual port 0,
// which may be either physical port 0 or 1
int physical_head = vc->heads[0].physical_head;
int crtc_idx;
if( vc->used_crtc[0] )
crtc_idx = 0;
else
crtc_idx = 1;
//SHOW_INFO( 3, "semaphore: %x", ai->si->ports[physical_port].vblank );
return ai->si->heads[physical_head].vblank;
return ai->si->crtc[crtc_idx].vblank;
//return B_ERROR;
}
@@ -30,7 +30,7 @@ static status_t init_common( int the_fd, bool accelerant_is_clone )
radeon_get_private_data gpd;
SHOW_FLOW0( 3, "" );
ai = malloc( sizeof( *ai ));
if( ai == NULL )
return B_NO_MEMORY;
@@ -151,7 +151,7 @@ status_t INIT_ACCELERANT( int the_fd )
result = init_common( the_fd, 0 );
if (result != B_OK)
goto err;
si = ai->si;
vc = ai->vc;
@@ -189,8 +189,8 @@ status_t INIT_ACCELERANT( int the_fd )
si->overlay_mgr.inuse = 0;
// mark overlay as inactive
si->active_overlay.head = -1;
si->pending_overlay.head = -1;
si->active_overlay.crtc_idx = -1;
si->pending_overlay.crtc_idx = -1;
// reset list of allocated overlays
vc->overlay_buffers = NULL;
+6 -3
View File
@@ -20,6 +20,8 @@ Addon radeon.accelerant : accelerants :
dpms.c
driver_wrapper.c
flat_panel.c
impactv.c
internal_tv_out.c
monitor_detection.c
monitor_routing.c
multimon.c
@@ -28,12 +30,13 @@ Addon radeon.accelerant : accelerants :
palette.c
pll.c
settings.cpp
tv_out.c
theatre_out.c
vesa_modes.c
: false
: libaccelerantscommon.a libgraphicscommon.a libradeon.a
: libaccelerantscommon.a libradeon.a
;
LinkSharedOSLibs radeon.accelerant : root be ;
LinkSharedOSLibs radeon.accelerant : be ;
Package haiku-radeon-cvs :
radeon.accelerant :
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
@@ -14,6 +14,7 @@
#include "crtc_regs.h"
#include "utils.h"
#include "set_mode.h"
// standard mode list
// all drivers contain this list - this should really be moved to
@@ -24,8 +25,10 @@
//#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
static const display_mode base_mode_list[] = {
// PAL
// test for PAL
//{ { 25175, 640, 656, 752, 816, 480, 490, 492, 625, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
// test for NTSC
//{ { 43956, 800, 824, 952, 992, 600, 632, 635, 740, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
@@ -35,6 +38,14 @@ static const display_mode base_mode_list[] = {
{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
{ { 25175, 640, 656, 752, 800, 400, 412, 414, 449, B_POSITIVE_VSYNC}, B_CMAP8, 640, 400, 0, 0, MODE_FLAGS}, /* 640x400 - www.epanorama.net/documents/pc/vga_timing.html) */
{ { 25175, 640, 656, 752, 800, 350, 387, 389, 449, B_POSITIVE_HSYNC}, B_CMAP8, 640, 350, 0, 0, MODE_FLAGS}, /* 640x350 - www.epanorama.net/documents/pc/vga_timing.html) */
// NTSC non-isometric resolution (isometric resolution is 640x480)
{ { 26720, 720, 736, 808, 896, 480, 481, 484, 497, B_POSITIVE_VSYNC}, B_CMAP8, 720, 480, 0, 0, MODE_FLAGS}, /* 720x480@60Hz according to GMTF */
// PAL resolutions
{ { 26570, 720, 736, 808, 896, 576, 577, 580, 593, B_POSITIVE_VSYNC}, B_CMAP8, 720, 576, 0, 0, MODE_FLAGS}, /* 720x576@50Hz according to GMTF */
{ { 28460, 768, 784, 864, 960, 576, 577, 580, 593, B_POSITIVE_VSYNC}, B_CMAP8, 768, 576, 0, 0, MODE_FLAGS}, /* 768x576@50Hz according to GMTF */
{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
@@ -47,6 +58,10 @@ static const display_mode base_mode_list[] = {
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
{ { 108000, 1280, 1376, 1488, 1800, 960, 961, 964, 1000, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X960X8.Z1) - not in Be's list */
{ { 148500, 1280, 1344, 1504, 1728, 960, 961, 964, 1011, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X960X8.Z1) - not in Be's list */
{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
@@ -59,7 +74,7 @@ static const display_mode base_mode_list[] = {
};
// convert Be colour space in Radeon data type
// convert Be colour space to Radeon data type
// returns true, if supported colour space
// space - Be colour space
// format - (out) Radeon data type
@@ -105,7 +120,8 @@ bool Radeon_GetFormat( int space, int *format, int *bpp )
return B_BAD_VALUE.
If the mode is both valid AND falls within the limits, return B_OK.
*/
status_t Radeon_ProposeDisplayMode( shared_info *si, physical_head *head,
status_t Radeon_ProposeDisplayMode(
shared_info *si, crtc_info *crtc,
general_pll_info *pll, display_mode *target,
const display_mode *low, const display_mode *high )
{
@@ -116,7 +132,7 @@ status_t Radeon_ProposeDisplayMode( shared_info *si, physical_head *head,
int format, bpp;
uint32 row_bytes;
int eff_virtual_width;
fp_info *flatpanel = &si->flatpanels[head->flatpanel_port];
fp_info *flatpanel = &si->flatpanels[crtc->flatpanel_port];
// save refresh rate - we want to leave this (artifical) value untouched
// don't use floating point, we are in kernel mode
@@ -133,7 +149,7 @@ status_t Radeon_ProposeDisplayMode( shared_info *si, physical_head *head,
// for flat panels, check maximum resolution;
// all the other tricks (like fixed resolution and resulting scaling)
// are done automagically by set_display_mode
if( (head->chosen_displays & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 ) {
if( (crtc->chosen_displays & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 ) {
if( target->timing.h_display > flatpanel->panel_xres )
target->timing.h_display = flatpanel->panel_xres;
@@ -141,6 +157,7 @@ status_t Radeon_ProposeDisplayMode( shared_info *si, physical_head *head,
target->timing.v_display = flatpanel->panel_yres;
}
/*
// the TV-Out encoder can "only" handle up to 1024x768
if( (head->chosen_displays & (dd_ctv | dd_stv)) != 0 ) {
if( target->timing.h_display > 1024 )
@@ -149,13 +166,14 @@ status_t Radeon_ProposeDisplayMode( shared_info *si, physical_head *head,
if( target->timing.v_display > 768 )
target->timing.v_display = 768;
}
*/
// validate horizontal timings
{
int h_sync_fudge, h_display, h_sync_start, h_sync_wid, h_total;
h_display = target->timing.h_display;
h_sync_fudge = Radeon_GetHSyncFudge( head, format );
h_sync_fudge = Radeon_GetHSyncFudge( crtc, format );
h_sync_start = target->timing.h_sync_start;
h_sync_wid = target->timing.h_sync_end - target->timing.h_sync_start;
h_total = target->timing.h_total;
@@ -431,7 +449,7 @@ static void checkAndAddMode( accelerator_info *ai, const display_mode *mode, boo
*dst = *mode;
dst->space = low.space = high.space = spaces[i];
if( Radeon_ProposeDisplayMode( si, &si->heads[0],
if( Radeon_ProposeDisplayMode( si, &si->crtc[0],
&si->pll, dst, &low, &high ) == B_OK )
{
si->mode_count++;
@@ -442,7 +460,7 @@ static void checkAndAddMode( accelerator_info *ai, const display_mode *mode, boo
*dst = *mode;
dst->space = spaces[i];
if( Radeon_ProposeDisplayMode( si, &si->heads[1],
if( Radeon_ProposeDisplayMode( si, &si->crtc[1],
&si->pll, dst, &low, &high ) == B_OK )
{
si->mode_count++;
@@ -480,11 +498,13 @@ static void checkAndAddMultiMode( accelerator_info *ai, const display_mode *mode
}
// add display mode of flat panel to official list
static void addFPMode( shared_info *si )
static void addFPMode( accelerator_info *ai )
{
shared_info *si = ai->si;
fp_info *fp_info = &si->flatpanels[0];
if( (si->connected_displays & (dd_dvi | dd_lvds)) != 0 ) {
if( (ai->vc->connected_displays & (dd_dvi | dd_lvds)) != 0 ) {
display_mode mode;
mode.virtual_width = mode.timing.h_display = fp_info->panel_xres;
@@ -555,7 +575,7 @@ status_t Radeon_CreateModeList( shared_info *si )
checkAndAddMultiMode( ai, &base_mode_list[i], false );
// plus fp mode
addFPMode( si );
addFPMode( ai );
// as we've created the list ourself, we don't clone it
ai->mode_list_area = si->mode_list_area;
@@ -596,7 +616,8 @@ status_t PROPOSE_DISPLAY_MODE( display_mode *target, const display_mode *low,
// via successive Propose_Display_Mode; though this doesn't do any _real_ harm
// it leads to annoying distortions on screen!!
Radeon_DetectDisplays( ai);
Radeon_SetupDefaultMonitorRouting( ai, Radeon_DifferentPorts( &tmp_target ) );
Radeon_SetupDefaultMonitorRouting(
ai, Radeon_DifferentPorts( &tmp_target ), vc->use_laptop_panel );
// transform to multi-screen mode first
Radeon_DetectMultiMode( vc, target );
@@ -613,7 +634,7 @@ status_t PROPOSE_DISPLAY_MODE( display_mode *target, const display_mode *low,
// we must assure that each ProposeMode call doesn't tweak the mode in
// a way that it cannot be handled by the other port anymore
result1 = Radeon_ProposeDisplayMode( si, &si->heads[vc->heads[0].physical_head],
result1 = Radeon_ProposeDisplayMode( si, &si->crtc[0],
&si->pll, target, low, high );
if( result1 == B_ERROR )
@@ -621,7 +642,7 @@ status_t PROPOSE_DISPLAY_MODE( display_mode *target, const display_mode *low,
if( Radeon_NeedsSecondPort( target )) {
// if both ports are used, make sure both can handle mode
result2 = Radeon_ProposeDisplayMode( si, &si->heads[vc->heads[1].physical_head],
result2 = Radeon_ProposeDisplayMode( si, &si->crtc[1],
&si->pll, target, low, high );
if( result2 == B_ERROR )
+172 -94
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
@@ -16,16 +16,19 @@
#include "crtc_regs.h"
#include <GraphicsDefs.h>
#include "crtc_regs.h"
#include "overlay_regs.h"
#include "capture_regs.h"
#include "rbbm_regs.h"
#include "dac_regs.h"
#include "set_mode.h"
#include <string.h>
// round virtual width up to next valid size
uint32 Radeon_RoundVWidth( int virtual_width, int bpp )
uint32 Radeon_RoundVWidth(
int virtual_width, int bpp )
{
// we have to make both the CRTC and the accelerator happy:
// - the CRTC wants virtual width in pixels to be a multiple of 8
@@ -58,26 +61,37 @@ static struct {
{ RADEON_OVR_CLR, 0 },
{ RADEON_OVR_WID_LEFT_RIGHT, 0 },
{ RADEON_OVR_WID_TOP_BOTTOM, 0 },
{ RADEON_OV0_SCALE_CNTL, 0 },
{ RADEON_OV0_SCALE_CNTL, 0 }, // disable overlay
{ RADEON_SUBPIC_CNTL, 0 },
{ RADEON_VIPH_CONTROL, 0 },
{ RADEON_I2C_CNTL_1, 0 },
//{ RADEON_GEN_INT_CNTL, 0 }, // VBI irqs are handled seperately
//{ RADEON_CAP0_TRIG_CNTL, 0 }, // leave capturing on during mode switch
};
static void Radeon_InitCommonRegs( accelerator_info *ai )
static void Radeon_InitCommonRegs(
accelerator_info *ai )
{
vuint8 *regs = ai->regs;
uint i;
for( i = 0; i < sizeof( common_regs) / sizeof( common_regs[0] ); ++i )
OUTREG( regs, common_regs[i].reg, common_regs[i].val );
// enable extended display modes
OUTREGP( regs, RADEON_CRTC_GEN_CNTL,
RADEON_CRTC_EXT_DISP_EN, ~RADEON_CRTC_EXT_DISP_EN );
// disable flat panel auto-centering
// (if we have a CRT on CRTC1, this must be disabled;
// if we have a flat panel on CRTC1, we setup CRTC manually, not
// using the auto-centre, automatic-sync-override magic)
OUTREG( regs, RADEON_CRTC_MORE_CNTL, 0 );
}
// set display mode of one head;
// port restrictions, like fixed-sync TFTs connected to it, are taken care of
void Radeon_SetMode( accelerator_info *ai, physical_head *head, display_mode *mode )
void Radeon_SetMode(
accelerator_info *ai, crtc_info *crtc, display_mode *mode, impactv_params *tv_params )
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
@@ -86,24 +100,28 @@ void Radeon_SetMode( accelerator_info *ai, physical_head *head, display_mode *mo
int bpp;
display_device_e disp_devices;
fp_info *fp_info;
port_regs values;
tv_params tv_params;
tv_standard tv_format = ts_ntsc;
tv_timing *tv_timing = &Radeon_std_tv_timing[tv_format];
bool internal_tv_encoder;
head->mode = *mode;
crtc_regs crtc_values;
pll_regs pll_values;
fp_regs fp_values;
impactv_regs impactv_values;
uint32 surface_cntl;
bool internal_tv_encoder;
pll_dividers dividers;
crtc->mode = *mode;
// don't destroy passed values, use our copy instead
mode = &head->mode;
mode = &crtc->mode;
disp_devices = head->chosen_displays;
fp_info = &si->flatpanels[head->flatpanel_port];
disp_devices = crtc->chosen_displays;
fp_info = &si->flatpanels[crtc->flatpanel_port];
// if using an flat panel or LCD, maximum resolution
// is determined by the physical resolution;
// also, all timing is fixed
if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext )) != 0 ) {
if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 ) {
if( mode->timing.h_display > fp_info->panel_xres )
mode->timing.h_display = fp_info->panel_xres;
if( mode->timing.v_display > fp_info->panel_yres )
@@ -118,18 +136,29 @@ void Radeon_SetMode( accelerator_info *ai, physical_head *head, display_mode *mo
mode->timing.pixel_clock = fp_info->dot_clock;
}
// TV-out supports at most 1024x768
if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
if( mode->timing.h_display > 1024 )
mode->timing.h_display = 1024;
if( mode->timing.v_display > 768 )
mode->timing.v_display = 768;
}
// if using TV-Out, the timing of the source signal must be tweaked to
// get proper timing
internal_tv_encoder = si->tv_chip != tc_external_rt1;
internal_tv_encoder = IS_INTERNAL_TV_OUT( si->tv_chip );
// we need higher accuracy then Be thought of;
// we need higher accuracy then Be thought of
mode->timing.pixel_clock *= 1000;
// TV stuff must be done first as it tweaks the display mode
if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
display_mode tweaked_mode;
Radeon_CalcTVParams( &si->pll, &tv_params, tv_timing, internal_tv_encoder,
Radeon_CalcImpacTVParams(
&si->pll, tv_params, vc->tv_standard, internal_tv_encoder,
mode, &tweaked_mode );
*mode = tweaked_mode;
@@ -143,90 +172,92 @@ void Radeon_SetMode( accelerator_info *ai, physical_head *head, display_mode *mo
// time to read original register content
// lock hardware so noone bothers us
Radeon_WaitForIdle( ai, true );
Radeon_ReadCRTCRegisters( ai, head, &values );
Radeon_ReadMonitorRoutingRegs( ai, head, &values );
if( (disp_devices & (dd_dvi | dd_lvds | dd_dvi_ext)) != 0 ) {
if( !head->is_crtc2 )
Radeon_ReadRMXRegisters( ai, &values );
if( crtc->crtc_idx == 0 )
Radeon_ReadRMXRegisters( ai, &fp_values );
Radeon_ReadFPRegisters( ai, &values );
Radeon_ReadFPRegisters( ai, &fp_values );
}
// calculate all hardware register values
Radeon_CalcCRTCRegisters( ai, head, mode, &values );
values.surface_cntl = RADEON_SURF_TRANSLATION_DIS;
// for flat panels, we may not have pixel clock if DDC data is missing;
// as we don't change effective resolution we can leave it as set by BIOS
if( mode->timing.pixel_clock ) {
Radeon_CalcPLLRegisters( &si->pll, mode/*->timing.pixel_clock / 10*/,
(/*(disp_devices & (dd_stv | dd_ctv)) != 0 ? &tv_params.crt_dividers : */NULL),
&values );
}
// for first CRTC1, we need to setup RMX properly
if( !head->is_crtc2 )
Radeon_CalcRMXRegisters( fp_info, mode,
(disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0,
&values );
if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 )
Radeon_CalcFPRegisters( ai, head, fp_info, &values );
if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
Radeon_CalcTVRegisters( ai, mode, tv_timing, &tv_params, &values,
head, internal_tv_encoder, tv_format );
// some register's content isn't created from scratch but
// only modified, so we need the original content first
if( internal_tv_encoder )
Radeon_InternalTVOutReadRegisters( ai, &impactv_values );
else
Radeon_TheatreReadTVRegisters( ai, &impactv_values );
}
Radeon_CalcMonitorRouting( ai, head, &values );
// calculate all hardware register values
Radeon_CalcCRTCRegisters( ai, crtc, mode, &crtc_values );
surface_cntl = RADEON_SURF_TRANSLATION_DIS;
if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
Radeon_CalcImpacTVRegisters( ai, mode, tv_params, &impactv_values,
crtc->crtc_idx, internal_tv_encoder, vc->tv_standard, disp_devices );
}
if( (disp_devices & (dd_stv | dd_ctv)) == 0 )
Radeon_CalcCRTPLLDividers( &si->pll, mode, &dividers );
else
dividers = tv_params->crt_dividers;
Radeon_CalcPLLRegisters( mode, &dividers, &pll_values );
// for first CRTC1, we need to setup RMX properly
if( crtc->crtc_idx == 0 )
Radeon_CalcRMXRegisters( fp_info, mode,
(disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0,
&fp_values );
if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 )
Radeon_CalcFPRegisters( ai, crtc, fp_info, &crtc_values, &fp_values );
// we don't use pixel clock anymore, so it can be reset to Be's kHz
mode->timing.pixel_clock /= 1000;
// write values to registers
// we first switch off all output, so the monitor(s) won't get invalid signals
Radeon_SetDPMS( ai, head, B_DPMS_SUSPEND );
Radeon_InitCommonRegs( ai );
Radeon_ProgramCRTCRegisters( ai, head, &values );
Radeon_ProgramCRTCRegisters( ai, crtc->crtc_idx, &crtc_values );
OUTREG( regs, RADEON_SURFACE_CNTL, surface_cntl );
OUTREG( regs, RADEON_SURFACE_CNTL, values.surface_cntl );
if( !head->is_crtc2 )
Radeon_ProgramRMXRegisters( ai, &values );
if( crtc->crtc_idx == 0 )
Radeon_ProgramRMXRegisters( ai, &fp_values );
if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 )
Radeon_ProgramFPRegisters( ai, head, fp_info, &values );
Radeon_ProgramFPRegisters( ai, crtc, fp_info, &fp_values );
//if( mode->timing.pixel_clock )
Radeon_ProgramPLL( ai, head, &values );
if( (disp_devices & (dd_ctv | dd_stv)) != 0 )
Radeon_ProgramTVRegisters( ai, &values, internal_tv_encoder );
Radeon_ProgramMonitorRouting( ai, head, &values );
Radeon_ProgramPLL( ai, crtc->crtc_idx, &pll_values );
head->active_displays = disp_devices;
if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
if( internal_tv_encoder )
Radeon_InternalTVOutProgramRegisters( ai, &impactv_values );
else
Radeon_TheatreProgramTVRegisters( ai, &impactv_values );
}
crtc->active_displays = disp_devices;
// programming is over, so hardware can be used again
RELEASE_BEN( si->cp.lock );
// well done - switch display(s) on
Radeon_SetDPMS( ai, head, B_DPMS_ON );
// overlay must be setup again after modeswitch (whoever was using it)
// TBD: this won't work if another virtual card was using it,
// but currently, virtual cards don't work anyway...
si->active_overlay.head = -1;
si->active_overlay.crtc_idx = -1;
}
// enable or disable VBlank interrupts
void Radeon_EnableIRQ( accelerator_info *ai, bool enable )
void Radeon_EnableIRQ(
accelerator_info *ai, bool enable )
{
shared_info *si = ai->si;
uint32 int_cntl, int_mask;
@@ -234,7 +265,7 @@ void Radeon_EnableIRQ( accelerator_info *ai, bool enable )
int_cntl = INREG( ai->regs, RADEON_GEN_INT_CNTL );
int_mask =
RADEON_CRTC_VBLANK_MASK
| (si->num_heads > 1 ? RADEON_CRTC2_VBLANK_MASK : 0);
| (si->num_crtc > 1 ? RADEON_CRTC2_VBLANK_MASK : 0);
if( enable )
int_cntl |= int_mask;
@@ -254,7 +285,8 @@ void Radeon_EnableIRQ( accelerator_info *ai, bool enable )
// public function: set display mode
status_t SET_DISPLAY_MODE( display_mode *mode_in )
status_t SET_DISPLAY_MODE(
display_mode *mode_in )
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
@@ -281,11 +313,16 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
// mode switches can take quite long and are visible,
// so avoid them if possible
if( memcmp( &mode, &vc->mode, sizeof( display_mode )) == 0 ) {
if( memcmp( &mode, &vc->mode, sizeof( display_mode )) == 0 &&
!vc->enforce_mode_change ) {
RELEASE_BEN( si->engine.lock );
return B_OK;
}
// this flag was set when some internal parameter has changed that
// affects effective display mode
vc->enforce_mode_change = false;
// make sure, we don't get disturbed
//Radeon_Finish( ai );
Radeon_EnableIRQ( ai, false );
@@ -318,9 +355,14 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
Radeon_VerifyMultiMode( vc, si, &mode );
// set main flags
vc->independant_heads = Radeon_NeedsSecondPort( &mode ) ? 2 : 1;
vc->independant_heads = vc->assigned_crtc[0] && si->crtc[0].chosen_displays != dd_none;
if( si->num_crtc > 1 )
vc->independant_heads += vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none;
vc->different_heads = Radeon_DifferentPorts( &mode );
SHOW_FLOW( 2, "independant heads: %d", vc->independant_heads );
SHOW_FLOW( 2, "independant heads: %d, different heads: %d",
vc->independant_heads, vc->different_heads );
vc->scroll = mode.flags & B_SCROLL;
SHOW_FLOW( 2, "scrolling %s", vc->scroll ? "enabled" : "disabled" );
@@ -372,14 +414,50 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
}
// multi-screen stuff
Radeon_InitMultiModeVars( vc, &mode );
Radeon_InitMultiModeVars( ai, &mode );
// GO!
Radeon_SetMode( ai, &si->heads[vc->heads[0].physical_head], &mode );
{
routing_regs routing_values;
impactv_params tv_params;
// we first switch off all output, so the monitor(s) won't get invalid signals
if( vc->assigned_crtc[0] ) {
// overwrite list of active displays to switch off displays
// someone else turned on
si->crtc[0].active_displays = vc->controlled_displays;
Radeon_SetDPMS( ai, 0, B_DPMS_SUSPEND );
}
if( vc->assigned_crtc[1] ) {
si->crtc[1].active_displays = vc->controlled_displays;
Radeon_SetDPMS( ai, 1, B_DPMS_SUSPEND );
}
// mark crtc that will be used from now on
vc->used_crtc[0] = vc->assigned_crtc[0] && si->crtc[0].chosen_displays != dd_none;
vc->used_crtc[1] = vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none;
// then change the mode
if( vc->used_crtc[0] )
Radeon_SetMode( ai, &si->crtc[0], &mode, &tv_params );
if( vc->used_crtc[1] )
Radeon_SetMode( ai, &si->crtc[1], &mode, &tv_params );
// setup signal routing
Radeon_ReadMonitorRoutingRegs( ai, &routing_values );
Radeon_CalcMonitorRouting( ai, &tv_params, &routing_values );
Radeon_ProgramMonitorRouting( ai, &routing_values );
// finally, switch display(s) on
if( vc->used_crtc[0] )
Radeon_SetDPMS( ai, 0, B_DPMS_ON );
if( vc->used_crtc[1] )
Radeon_SetDPMS( ai, 1, B_DPMS_ON );
OUTREGP( ai->regs, RADEON_CRTC_EXT_CNTL, 0, ~RADEON_CRTC_DISPLAY_DIS );
}
if( vc->independant_heads > 1 )
Radeon_SetMode( ai, &si->heads[vc->heads[1].physical_head], &mode );
SHOW_FLOW( 3, "pitch=%ld", vc->pitch );
// we'll modify bits of this reg, so save it for async access
@@ -399,18 +477,18 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
Radeon_MoveDisplay( ai, mode.h_display_start, mode.v_display_start );
// set standard palette in direct-colour modes
Radeon_InitPalette( ai, &si->heads[vc->heads[0].physical_head] );
if( vc->independant_heads > 1 )
Radeon_InitPalette( ai, &si->heads[vc->heads[1].physical_head] );
if( vc->used_crtc[0] )
Radeon_InitPalette( ai, 0 );
if( vc->used_crtc[1] )
Radeon_InitPalette( ai, 1 );
// initialize cursor data
Radeon_SetCursorColors( ai, &si->heads[vc->heads[0].physical_head] );
if( vc->independant_heads > 1 )
Radeon_SetCursorColors( ai, &si->heads[vc->heads[1].physical_head] );
if( vc->used_crtc[0] )
Radeon_SetCursorColors( ai, 0 );
if( vc->used_crtc[1] )
Radeon_SetCursorColors( ai, 1 );
// sync should be settled now, so we can reenable IRQs
// TBD: IRQ handling doesn't work correctly and doesn't make sense with two
// displays connected, so let's leave them disabled for now
Radeon_EnableIRQ( ai, true );
RELEASE_BEN( si->engine.lock );
+42 -71
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2005, Thomas Kurschel
Part of Radeon accelerant
@@ -10,37 +10,35 @@
#include "radeon_accelerant.h"
#include "mmio.h"
#include "crtc_regs.h"
#include "dac_regs.h"
#include "GlobalData.h"
// read old CRTC register content
void Radeon_ReadCRTCRegisters( accelerator_info *ai, physical_head *head,
port_regs *values )
{
vuint8 *regs = ai->regs;
// only CRTC_EXT_CNTL is programmed by someone else (namely the monitor
// router); if more registers are affected, you must read them here too!
if( !head->is_crtc2 ) {
values->crtc_ext_cntl = INREG( regs, RADEON_CRTC_EXT_CNTL );
}
}
#include "set_mode.h"
// hammer CRTC registers
void Radeon_ProgramCRTCRegisters( accelerator_info *ai, physical_head *head,
port_regs *values )
void Radeon_ProgramCRTCRegisters( accelerator_info *ai, int crtc_idx,
crtc_regs *values )
{
vuint8 *regs = ai->regs;
SHOW_FLOW0( 2, "" );
if( head->is_crtc2 ) {
if( crtc_idx == 0 ) {
OUTREGP( regs, RADEON_CRTC_GEN_CNTL, values->crtc_gen_cntl,
RADEON_CRTC_EXT_DISP_EN );
OUTREG( regs, RADEON_CRTC_H_TOTAL_DISP, values->crtc_h_total_disp );
OUTREG( regs, RADEON_CRTC_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid );
OUTREG( regs, RADEON_CRTC_V_TOTAL_DISP, values->crtc_v_total_disp );
OUTREG( regs, RADEON_CRTC_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid );
OUTREG( regs, RADEON_CRTC_OFFSET_CNTL, values->crtc_offset_cntl );
OUTREG( regs, RADEON_CRTC_PITCH, values->crtc_pitch );
} else {
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, values->crtc_gen_cntl,
RADEON_CRTC2_VSYNC_DIS |
RADEON_CRTC2_HSYNC_DIS |
RADEON_CRTC2_DISP_DIS );
RADEON_CRTC2_DISP_DIS |
RADEON_CRTC2_CRT2_ON );
OUTREG( regs, RADEON_CRTC2_H_TOTAL_DISP, values->crtc_h_total_disp );
OUTREG( regs, RADEON_CRTC2_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid );
@@ -48,37 +46,18 @@ void Radeon_ProgramCRTCRegisters( accelerator_info *ai, physical_head *head,
OUTREG( regs, RADEON_CRTC2_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid );
OUTREG( regs, RADEON_CRTC2_OFFSET_CNTL, values->crtc_offset_cntl );
OUTREG( regs, RADEON_CRTC2_PITCH, values->crtc_pitch );
} else {
OUTREG( regs, RADEON_CRTC_GEN_CNTL, values->crtc_gen_cntl );
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, values->crtc_ext_cntl,
RADEON_CRTC_VSYNC_DIS |
RADEON_CRTC_HSYNC_DIS |
RADEON_CRTC_DISPLAY_DIS |
RADEON_CRTC_CRT_ON );
OUTREGP( regs, RADEON_DAC_CNTL, values->dac_cntl,
RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_BLANKING );
OUTREG( regs, RADEON_CRTC_H_TOTAL_DISP, values->crtc_h_total_disp );
OUTREG( regs, RADEON_CRTC_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid );
OUTREG( regs, RADEON_CRTC_V_TOTAL_DISP, values->crtc_v_total_disp );
OUTREG( regs, RADEON_CRTC_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid );
OUTREG( regs, RADEON_CRTC_OFFSET_CNTL, values->crtc_offset_cntl );
OUTREG( regs, RADEON_CRTC_PITCH, values->crtc_pitch );
}
}
// get required hsync delay depending on bit depth and output device
uint16 Radeon_GetHSyncFudge( physical_head *head, int datatype )
uint16 Radeon_GetHSyncFudge( crtc_info *crtc, int datatype )
{
static int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
static int hsync_fudge_fp[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 };
// there is an sync delay which depends on colour-depth and output device
if( (head->chosen_displays & (dd_dvi | dd_dvi_ext | dd_lvds )) != 0 )
if( (crtc->chosen_displays & (dd_dvi | dd_dvi_ext | dd_lvds )) != 0 )
return hsync_fudge_fp[datatype - 1];
else
return hsync_fudge_default[datatype - 1];
@@ -86,8 +65,8 @@ uint16 Radeon_GetHSyncFudge( physical_head *head, int datatype )
// calculate CRTC register content
void Radeon_CalcCRTCRegisters( accelerator_info *ai, physical_head *head,
display_mode *mode, port_regs *values )
void Radeon_CalcCRTCRegisters( accelerator_info *ai, crtc_info *crtc,
display_mode *mode, crtc_regs *values )
{
virtual_card *vc = ai->vc;
int hsync_start;
@@ -95,29 +74,21 @@ void Radeon_CalcCRTCRegisters( accelerator_info *ai, physical_head *head,
int hsync_fudge;
int vsync_wid;
hsync_fudge = Radeon_GetHSyncFudge( head, vc->datatype );
hsync_fudge = Radeon_GetHSyncFudge( crtc, vc->datatype );
if( head->is_crtc2 ) {
values->crtc_gen_cntl = (RADEON_CRTC2_EN
| RADEON_CRTC2_CRT2_ON
if( crtc->crtc_idx == 0 ) {
// here, we should set interlace/double scan mode
// but we don't support them (anyone missing them?)
values->crtc_gen_cntl =
RADEON_CRTC_EN
| (vc->datatype << 8);
} else {
values->crtc_gen_cntl = RADEON_CRTC2_EN
| (vc->datatype << 8)
| (0/*doublescan*/ ? RADEON_CRTC2_DBL_SCAN_EN : 0)
| ((mode->timing.flags & B_TIMING_INTERLACED)
? RADEON_CRTC2_INTERLACE_EN : 0));
} else {
// here, we should set interlace/double scan mode
// but we don't support them (anyone missing them?)
values->crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN
| RADEON_CRTC_EN
| (vc->datatype << 8));
values->crtc_ext_cntl =
RADEON_VGA_ATI_LINEAR |
RADEON_XCRT_CNT_EN;
values->dac_cntl = RADEON_DAC_MASK_ALL
| RADEON_DAC_VGA_ADR_EN
| RADEON_DAC_8BIT_EN;
? RADEON_CRTC2_INTERLACE_EN : 0);
}
values->crtc_h_total_disp =
@@ -156,19 +127,19 @@ void Radeon_CalcCRTCRegisters( accelerator_info *ai, physical_head *head,
// update shown are of one port
static void moveOneDisplay( accelerator_info *ai, virtual_head *virtual_head )
static void moveOneDisplay( accelerator_info *ai, crtc_info *crtc )
{
virtual_card *vc = ai->vc;
uint32 offset;
offset = (vc->mode.v_display_start + virtual_head->rel_y) * vc->pitch +
(vc->mode.h_display_start + virtual_head->rel_x) * vc->bpp +
offset = (vc->mode.v_display_start + crtc->rel_y) * vc->pitch +
(vc->mode.h_display_start + crtc->rel_x) * vc->bpp +
vc->fb_offset;
SHOW_FLOW( 3, "Setting address %x on port %d",
offset, virtual_head->physical_head );
offset, crtc->crtc_idx );
OUTREG( ai->regs, virtual_head->physical_head ? RADEON_CRTC2_OFFSET : RADEON_CRTC_OFFSET, offset );
OUTREG( ai->regs, crtc->crtc_idx == 0 ? RADEON_CRTC_OFFSET : RADEON_CRTC2_OFFSET, offset );
}
// internal function: pan display
@@ -189,10 +160,10 @@ status_t Radeon_MoveDisplay( accelerator_info *ai, uint16 h_display_start, uint1
vc->mode.v_display_start = v_display_start;
// do it
moveOneDisplay( ai, &vc->heads[0] );
if( vc->independant_heads > 1 )
moveOneDisplay( ai, &vc->heads[1] );
if( vc->used_crtc[0] )
moveOneDisplay( ai, &ai->si->crtc[0] );
if( vc->used_crtc[1] )
moveOneDisplay( ai, &ai->si->crtc[1] );
// overlay position must be adjusted
Radeon_UpdateOverlay( ai );
+140 -50
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
@@ -13,6 +13,8 @@
#include "fp_regs.h"
#include "pll_regs.h"
#include "pll_access.h"
#include "tv_out_regs.h"
#include "theatre_regs.h"
#include "GlobalData.h"
@@ -20,15 +22,14 @@
status_t SET_DPMS_MODE(uint32 dpms_flags)
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
status_t result1, result2;
result1 = Radeon_SetDPMS( ai, &si->heads[vc->heads[0].physical_head], dpms_flags );
if( vc->independant_heads > 1 )
result2 = Radeon_SetDPMS( ai, &si->heads[vc->heads[1].physical_head], dpms_flags );
else
status_t
result1 = B_OK,
result2 = B_OK;
if( vc->used_crtc[0] )
result1 = Radeon_SetDPMS( ai, 0, dpms_flags );
if( vc->used_crtc[0] )
result1 = Radeon_SetDPMS( ai, 0, dpms_flags );
if( result1 == B_OK && result2 == B_OK )
return B_OK;
@@ -46,8 +47,8 @@ uint32 DPMS_CAPABILITIES(void)
// public function: get current DPMS mode
uint32 DPMS_MODE(void)
{
// we just ask the primary head what status it is in
return Radeon_GetDPMS( ai, &ai->si->heads[ai->vc->heads[0].physical_head] );
// we just ask the primary virtual head what status it is in
return Radeon_GetDPMS( ai, ai->vc->used_crtc[0] ? 0 : 1 );
}
@@ -137,14 +138,56 @@ static void Radeon_SetDPMS_FP2( accelerator_info *ai, int mode )
}
// set DPMS mode for first port
// set DPMS mode for CRT DAC.
// warning: the CRTC-DAC only obbeys this setting if
// connected to CRTC1, else it collides with TV-DAC
static void Radeon_SetDPMS_CRT( accelerator_info *ai, int mode )
{
vuint8 *regs = ai->regs;
switch( mode ) {
case B_DPMS_ON:
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, ~RADEON_CRTC_DISPLAY_DIS );
break;
case B_DPMS_STAND_BY:
case B_DPMS_SUSPEND:
case B_DPMS_OFF:
OUTREGP( regs, RADEON_CRTC_EXT_CNTL,
RADEON_CRTC_DISPLAY_DIS, ~RADEON_CRTC_DISPLAY_DIS );
break;
}
}
// set DPMS mode for TV-DAC in CRT mode
// warning: if the CRT-DAC is connected to CRTC2, it is
// affected by this setting too
static void Radeon_SetDPMS_TVCRT( accelerator_info *ai, int mode )
{
vuint8 *regs = ai->regs;
switch( mode ) {
case B_DPMS_ON:
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_DISP_DIS );
break;
case B_DPMS_STAND_BY:
case B_DPMS_SUSPEND:
case B_DPMS_OFF:
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL,
RADEON_CRTC2_DISP_DIS, ~RADEON_CRTC2_DISP_DIS );
break;
}
}
// set DPMS mode for first CRTC
static void Radeon_SetDPMS_CRTC1( accelerator_info *ai, int mode )
{
vuint8 *regs = ai->regs;
int mask = RADEON_CRTC_DISPLAY_DIS
| RADEON_CRTC_HSYNC_DIS
| RADEON_CRTC_VSYNC_DIS;
uint32 mask = RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_VSYNC_DIS;
switch( mode ) {
case B_DPMS_ON:
@@ -154,29 +197,42 @@ static void Radeon_SetDPMS_CRTC1( accelerator_info *ai, int mode )
case B_DPMS_STAND_BY:
/* Screen: Off; HSync: Off, VSync: On */
OUTREGP( regs, RADEON_CRTC_EXT_CNTL,
RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS, ~mask );
RADEON_CRTC_HSYNC_DIS, ~mask );
break;
case B_DPMS_SUSPEND:
/* Screen: Off; HSync: On, VSync: Off */
OUTREGP( regs, RADEON_CRTC_EXT_CNTL,
RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS, ~mask );
RADEON_CRTC_VSYNC_DIS, ~mask );
break;
case B_DPMS_OFF:
/* Screen: Off; HSync: Off, VSync: Off */
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, mask, ~mask );
break;
}
// disable/enable memory requests and cursor
switch( mode ) {
case B_DPMS_ON:
/* Screen: On; HSync: On, VSync: On */
OUTREGP( regs, RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B );
Radeon_ShowCursor( ai, 0 );
break;
case B_DPMS_STAND_BY:
case B_DPMS_SUSPEND:
case B_DPMS_OFF:
OUTREGP( regs, RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B,
~(RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_CUR_EN) );
break;
}
}
// set DPMS mode of second port
static void Radeon_SetDPMS_CRTC2( accelerator_info *di, int mode )
// set DPMS mode of second CRTC
static void Radeon_SetDPMS_CRTC2( accelerator_info *ai, int mode )
{
vuint8 *regs = di->regs;
vuint8 *regs = ai->regs;
int mask = RADEON_CRTC2_DISP_DIS
| RADEON_CRTC2_HSYNC_DIS
| RADEON_CRTC2_VSYNC_DIS;
int mask = RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_VSYNC_DIS;
switch( mode ) {
case B_DPMS_ON:
@@ -186,36 +242,54 @@ static void Radeon_SetDPMS_CRTC2( accelerator_info *di, int mode )
case B_DPMS_STAND_BY:
/* Screen: Off; HSync: Off, VSync: On */
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL,
RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS, ~mask );
RADEON_CRTC2_HSYNC_DIS, ~mask );
break;
case B_DPMS_SUSPEND:
/* Screen: Off; HSync: On, VSync: Off */
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL,
RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS, ~mask );
RADEON_CRTC2_VSYNC_DIS, ~mask );
break;
case B_DPMS_OFF:
/* Screen: Off; HSync: Off, VSync: Off */
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, mask, ~mask );
break;
}
switch( mode ) {
case B_DPMS_ON:
/* Screen: On; HSync: On, VSync: On */
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_DISP_REQ_EN_B );
Radeon_ShowCursor( ai, 1 );
break;
case B_DPMS_STAND_BY:
case B_DPMS_SUSPEND:
case B_DPMS_OFF:
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_DISP_REQ_EN_B,
~(RADEON_CRTC2_DISP_REQ_EN_B | RADEON_CRTC2_CUR_EN) );
break;
}
}
// set DPMS mode of TV-out
static void Radeon_SetDPMS_TVOUT( accelerator_info *ai, int mode )
{
// we set to gain either to 0 for blank or 1 for normal operation
if( IS_INTERNAL_TV_OUT( ai->si->tv_chip )) {
OUTREG( ai->regs, RADEON_TV_LINEAR_GAIN_SETTINGS,
mode == B_DPMS_ON ? 0x01000100 : 0 );
} else {
Radeon_VIPWrite( ai, ai->si->theatre_channel, RADEON_TV_LINEAR_GAIN_SETTINGS,
mode == B_DPMS_ON ? 0x01000100 : 0 );
}
}
// set DPMS mode of one port
// engine lock is assumed to be hold
status_t Radeon_SetDPMS( accelerator_info *ai, physical_head *head, int mode )
status_t Radeon_SetDPMS( accelerator_info *ai, int crtc_idx, int mode )
{
/* // if we have a laptop panel
// and we have a second screen connected
// and they both show the same content,
// then switch the laptop display always off
if( ai->si->ports[port->physical_port].disp_type == dt_lvds &&
ai->vc->independant_ports > 1 &&
ai->vc->different_ports == 1 )
{
mode = B_DPMS_OFF;
}*/
crtc_info *crtc = &ai->si->crtc[crtc_idx];
// test validity of mode once and for all
switch( mode ) {
case B_DPMS_ON:
@@ -227,18 +301,34 @@ status_t Radeon_SetDPMS( accelerator_info *ai, physical_head *head, int mode )
return B_BAD_VALUE;
}
if( head->is_crtc2 )
Radeon_SetDPMS_CRTC2( ai, mode );
else
if( crtc_idx == 0 )
Radeon_SetDPMS_CRTC1( ai, mode );
if( (head->active_displays & dd_lvds) != 0 )
else
Radeon_SetDPMS_CRTC2( ai, mode );
// possible ASIC bug: if CRT-DAC is connected to CRTC1, it obbeys
// RADEON_CRTC_DISPLAY_DIS; if it is connected to CRTC2, to
// RADEON_CRTC2_DISP_DIS - i.e. it follows the CRTC;
// but the TV-DAC always listens to RADEON_CRTC2_DISP_DIS, independant
// of the CRTC it gets its signal from;
// this is a guarantee that two virtual cards will collide!
if( crtc_idx == 0 || 1/* && (crtc->active_displays & dd_crt) != 0 */)
Radeon_SetDPMS_CRT( ai, mode );
if( crtc_idx == 1 || (crtc->active_displays & (dd_tv_crt | dd_ctv | dd_stv)) != 0 )
Radeon_SetDPMS_TVCRT( ai, mode );
// TV-Out ignores DPMS completely, including the blank-screen trick
if( (crtc->active_displays & (dd_ctv | dd_stv)) != 0 )
Radeon_SetDPMS_TVOUT( ai, mode );
if( (crtc->active_displays & dd_lvds) != 0 )
Radeon_SetDPMS_LVDS( ai, mode );
if( (head->active_displays & dd_dvi) != 0 )
if( (crtc->active_displays & dd_dvi) != 0 )
Radeon_SetDPMS_DVI( ai, mode );
if( (head->active_displays & dd_dvi_ext) != 0 )
if( (crtc->active_displays & dd_dvi_ext) != 0 )
Radeon_SetDPMS_FP2( ai, mode );
return B_OK;
@@ -246,7 +336,7 @@ status_t Radeon_SetDPMS( accelerator_info *ai, physical_head *head, int mode )
// get DPMS mode of first port
uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di )
static uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di )
{
uint32 tmp;
@@ -266,7 +356,7 @@ uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di )
// get DPMS mode of second port
uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di )
static uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di )
{
uint32 tmp;
@@ -286,10 +376,10 @@ uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di )
// get DPMS mode of one port
uint32 Radeon_GetDPMS( accelerator_info *ai, physical_head *head )
uint32 Radeon_GetDPMS( accelerator_info *ai, int crtc_idx )
{
if( head->is_crtc2 )
return Radeon_GetDPMS_CRTC2( ai );
else
if( crtc_idx == 0 )
return Radeon_GetDPMS_CRTC1( ai );
else
return Radeon_GetDPMS_CRTC2( ai );
}
@@ -39,6 +39,7 @@ status_t Radeon_VIPRead( accelerator_info *ai, uint channel, uint address, uint3
vr.magic = RADEON_PRIVATE_DATA_MAGIC;
vr.channel = channel;
vr.address = address;
vr.lock = false;
res = ioctl( ai->fd, RADEON_VIPREAD, &vr, sizeof( vr ));
@@ -57,6 +58,7 @@ status_t Radeon_VIPWrite( accelerator_info *ai, uint8 channel, uint address, uin
vw.channel = channel;
vw.address = address;
vw.data = data;
vw.lock = false;
return ioctl( ai->fd, RADEON_VIPWRITE, &vw, sizeof( vw ));
}
+28 -27
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
@@ -10,12 +10,13 @@
#include "radeon_accelerant.h"
#include "mmio.h"
#include "fp_regs.h"
#include "memcntrl_regs.h"
#include "utils.h"
#include "crtc_regs.h"
#include "pll_regs.h"
#include "set_mode.h"
void Radeon_ReadRMXRegisters( accelerator_info *ai, port_regs *values )
void Radeon_ReadRMXRegisters(
accelerator_info *ai, fp_regs *values )
{
vuint8 *regs = ai->regs;
@@ -23,7 +24,8 @@ void Radeon_ReadRMXRegisters( accelerator_info *ai, port_regs *values )
values->fp_vert_stretch = INREG( regs, RADEON_FP_VERT_STRETCH );
}
void Radeon_CalcRMXRegisters( fp_info *flatpanel, display_mode *mode, bool use_rmx, port_regs *values )
void Radeon_CalcRMXRegisters(
fp_info *flatpanel, display_mode *mode, bool use_rmx, fp_regs *values )
{
uint xres = mode->timing.h_display;
uint yres = mode->timing.v_display;
@@ -100,7 +102,8 @@ void Radeon_CalcRMXRegisters( fp_info *flatpanel, display_mode *mode, bool use_r
}
// write RMX registers
void Radeon_ProgramRMXRegisters( accelerator_info *ai, port_regs *values )
void Radeon_ProgramRMXRegisters(
accelerator_info *ai, fp_regs *values )
{
vuint8 *regs = ai->regs;
@@ -109,7 +112,8 @@ void Radeon_ProgramRMXRegisters( accelerator_info *ai, port_regs *values )
}
void Radeon_ReadFPRegisters( accelerator_info *ai, port_regs *values )
void Radeon_ReadFPRegisters(
accelerator_info *ai, fp_regs *values )
{
vuint8 *regs = ai->regs;
@@ -128,18 +132,19 @@ void Radeon_ReadFPRegisters( accelerator_info *ai, port_regs *values )
// calculcate flat panel crtc registers;
// must be called after normal CRTC registers are determined
void Radeon_CalcFPRegisters( accelerator_info *ai, physical_head *head,
fp_info *fp_port, port_regs *values )
void Radeon_CalcFPRegisters(
accelerator_info *ai, crtc_info *crtc,
fp_info *fp_port, crtc_regs *crtc_values, fp_regs *values )
{
// setup synchronization position
// (most values are ignored according to fp_gen_cntl, but at least polarity
// and pixel precise horizontal sync position are always used)
if( fp_port->is_fp2 ) {
values->fp2_h_sync_strt_wid = values->crtc_h_sync_strt_wid;
values->fp2_v_sync_strt_wid = values->crtc_v_sync_strt_wid;
values->fp2_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid;
values->fp2_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid;
} else {
values->fp_h_sync_strt_wid = values->crtc_h_sync_strt_wid;
values->fp_v_sync_strt_wid = values->crtc_v_sync_strt_wid;
values->fp_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid;
values->fp_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid;
}
if( fp_port->is_fp2 )
@@ -147,8 +152,7 @@ void Radeon_CalcFPRegisters( accelerator_info *ai, physical_head *head,
else {
// setup magic CRTC shadowing
values->fp_gen_cntl &=
~(RADEON_FP_SEL_CRTC2 |
RADEON_FP_RMX_HVSYNC_CONTROL_EN |
~(RADEON_FP_RMX_HVSYNC_CONTROL_EN |
RADEON_FP_DFP_SYNC_SEL |
RADEON_FP_CRT_SYNC_SEL |
RADEON_FP_CRTC_LOCK_8DOT |
@@ -161,7 +165,7 @@ void Radeon_CalcFPRegisters( accelerator_info *ai, physical_head *head,
}
// enable proper transmitter
if( (head->chosen_displays & dd_lvds) != 0 ) {
if( (crtc->chosen_displays & dd_lvds) != 0 ) {
// using LVDS means there cannot be a DVI monitor
values->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON);
values->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
@@ -188,18 +192,20 @@ void Radeon_CalcFPRegisters( accelerator_info *ai, physical_head *head,
// write flat panel registers
void Radeon_ProgramFPRegisters( accelerator_info *ai, physical_head *head,
fp_info *fp_port, port_regs *values )
void Radeon_ProgramFPRegisters(
accelerator_info *ai, crtc_info *crtc,
fp_info *fp_port, fp_regs *values )
{
shared_info *si = ai->si;
vuint8 *regs = ai->regs;
SHOW_FLOW0( 2, "" );
OUTREG( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl );
OUTREGP( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl, RADEON_FP_SEL_CRTC2 );
if( fp_port->is_fp2 ) {
OUTREG( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl );
OUTREGP( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl,
RADEON_FP2_SOURCE_SEL_CRTC2 | RADEON_FP2_SRC_SEL_CRTC2 );
OUTREG( regs, RADEON_FP_H2_SYNC_STRT_WID, values->fp2_h_sync_strt_wid );
OUTREG( regs, RADEON_FP_V2_SYNC_STRT_WID, values->fp2_v_sync_strt_wid );
} else {
@@ -209,18 +215,13 @@ void Radeon_ProgramFPRegisters( accelerator_info *ai, physical_head *head,
// workaround for old AIW Radeon having display buffer underflow
// in conjunction with DVI
if( si->num_heads == 1 ) {
if( si->asic == rt_r100 ) {
OUTREG( regs, RADEON_GRPH_BUFFER_CNTL,
INREG( regs, RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000);
}
if( (head->chosen_displays & dd_lvds) != 0 ) {
if( (crtc->chosen_displays & dd_lvds) != 0 ) {
OUTREGP( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl,
RADEON_LVDS_ON | RADEON_LVDS_BLON );
}
// disable auto-centering
// (we setup everything ourself, and if we switch from flat panel to CRT
// on CRTC1, we don't need this stuff anyway)
OUTREG( regs, RADEON_CRTC_MORE_CNTL, 0 );
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,272 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Part of Radeon accelerant
Programming of internal TV-out unit
*/
#include "radeon_interface.h"
#include "radeon_accelerant.h"
#include "tv_out_regs.h"
#include "pll_access.h"
#include "mmio.h"
#include "utils.h"
#include "set_mode.h"
#include <stdlib.h>
// mapping of offset in impactv_regs to register address
typedef struct register_mapping {
uint16 address; // register address
uint16 offset; // offset in impactv_regs
} register_mapping;
// internal TV-encoder:
// registers to write before programming PLL
static const register_mapping intern_reg_mapping_before_pll[] = {
{ RADEON_TV_MASTER_CNTL, offsetof( impactv_regs, tv_master_cntl ) },
{ RADEON_TV_HRESTART, offsetof( impactv_regs, tv_hrestart ) },
{ RADEON_TV_VRESTART, offsetof( impactv_regs, tv_vrestart ) },
{ RADEON_TV_FRESTART, offsetof( impactv_regs, tv_frestart ) },
{ RADEON_TV_FTOTAL, offsetof( impactv_regs, tv_ftotal ) },
{ 0, 0 }
};
// PLL registers to program
static const register_mapping intern_reg_mapping_pll[] = {
{ RADEON_TV_PLL_CNTL, offsetof( impactv_regs, tv_tv_pll_cntl ) },
{ RADEON_TV_PLL_CNTL1, offsetof( impactv_regs, tv_pll_cntl1 ) },
{ RADEON_TV_PLL_FINE_CNTL, offsetof( impactv_regs, tv_pll_fine_cntl ) },
{ 0, 0 }
};
// registers to write after programming of PLL
static const register_mapping intern_reg_mapping_after_pll[] = {
{ RADEON_TV_HTOTAL, offsetof( impactv_regs, tv_htotal ) },
{ RADEON_TV_HDISP, offsetof( impactv_regs, tv_hdisp ) },
{ RADEON_TV_HSTART, offsetof( impactv_regs, tv_hstart ) },
{ RADEON_TV_VTOTAL, offsetof( impactv_regs, tv_vtotal ) },
{ RADEON_TV_VDISP, offsetof( impactv_regs, tv_vdisp ) },
{ RADEON_TV_TIMING_CNTL, offsetof( impactv_regs, tv_timing_cntl ) },
{ RADEON_TV_VSCALER_CNTL1, offsetof( impactv_regs, tv_vscaler_cntl1 ) },
{ RADEON_TV_VSCALER_CNTL2, offsetof( impactv_regs, tv_vscaler_cntl2 ) },
{ RADEON_TV_Y_SAW_TOOTH_CNTL, offsetof( impactv_regs, tv_y_saw_tooth_cntl ) },
{ RADEON_TV_Y_RISE_CNTL, offsetof( impactv_regs, tv_y_rise_cntl ) },
{ RADEON_TV_Y_FALL_CNTL, offsetof( impactv_regs, tv_y_fall_cntl ) },
{ RADEON_TV_MODULATOR_CNTL1, offsetof( impactv_regs, tv_modulator_cntl1 ) },
{ RADEON_TV_MODULATOR_CNTL2, offsetof( impactv_regs, tv_modulator_cntl2 ) },
{ RADEON_TV_RGB_CNTL, offsetof( impactv_regs, tv_rgb_cntl ) },
{ RADEON_TV_UV_ADR, offsetof( impactv_regs, tv_uv_adr ) },
{ RADEON_TV_PRE_DAC_MUX_CNTL, offsetof( impactv_regs, tv_pre_dac_mux_cntl ) },
{ RADEON_TV_CRC_CNTL, offsetof( impactv_regs, tv_crc_cntl ) },
{ 0, 0 }
};
// registers to write when things settled down
static const register_mapping intern_reg_mapping_finish[] = {
{ RADEON_TV_GAIN_LIMIT_SETTINGS, offsetof( impactv_regs, tv_gain_limit_settings ) },
{ RADEON_TV_LINEAR_GAIN_SETTINGS, offsetof( impactv_regs, tv_linear_gain_settings ) },
{ RADEON_TV_UPSAMP_AND_GAIN_CNTL, offsetof( impactv_regs, tv_upsamp_and_gain_cntl ) },
{ RADEON_TV_DAC_CNTL, offsetof( impactv_regs, tv_dac_cntl ) },
{ RADEON_TV_MASTER_CNTL, offsetof( impactv_regs, tv_master_cntl ) },
{ 0, 0 }
};
// write list of MM I/O registers
static void writeMMIORegList(
accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
{
vuint8 *regs = ai->regs;
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
/*SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );*/
OUTREG( regs, mapping->address, *(uint32 *)((char *)(values) + mapping->offset) );
}
//snooze( 1000000 );
}
// write list of PLL registers
static void writePLLRegList(
accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
{
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
/*SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );*/
Radeon_OUTPLL( ai->regs, ai->si->asic,
mapping->address, *(uint32 *)((char *)(values) + mapping->offset) );
}
//snooze( 1000000 );
}
// read timing FIFO
static uint32 Radeon_InternalTVOutReadFIFO(
accelerator_info *ai, uint16 addr )
{
vuint8 *regs = ai->regs;
bigtime_t start_time;
uint32 res = ~0;
//SHOW_FLOW( 2, "addr=%d", addr );
OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_RD);
start_time = system_time();
do {
uint32 status;
status = INREG( regs, RADEON_TV_HOST_RD_WT_CNTL );
if( (status & RADEON_TV_HOST_RD_WT_CNTL_RD_ACK) != 0 )
break;
} while( system_time() - start_time < 2000000 );
OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, 0);
res = INREG( regs, RADEON_TV_HOST_READ_DATA );
//SHOW_FLOW( 2, "res=%x %x", res >> 14, res & 0x3fff );
return res;
}
// write to timing FIFO
static void Radeon_InternalTVOutWriteFIFO(
accelerator_info *ai, uint16 addr, uint32 value )
{
vuint8 *regs = ai->regs;
bigtime_t start_time;
//readFIFO( ai, addr, internal_encoder );
//SHOW_FLOW( 2, "addr=%d, value=%x %x", addr, value >> 14, value & 0x3fff );
OUTREG( regs, RADEON_TV_HOST_WRITE_DATA, value );
OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_WT );
start_time = system_time();
do {
uint32 status;
status = INREG( regs, RADEON_TV_HOST_RD_WT_CNTL );
if( (status & RADEON_TV_HOST_RD_WT_CNTL_WT_ACK) != 0 )
break;
} while( system_time() - start_time < 2000000 );
OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, 0 );
}
// program TV-Out registers
void Radeon_InternalTVOutProgramRegisters(
accelerator_info *ai, impactv_regs *values )
{
uint32 orig_tv_master_cntl = values->tv_master_cntl;
SHOW_FLOW0( 2, "" );
// disable TV-out when registers are setup
// it gets enabled again when things have settled down
values->tv_master_cntl |=
RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST |
RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST |
RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST |
RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST;
writeMMIORegList( ai, values, intern_reg_mapping_before_pll );
writePLLRegList( ai, values, intern_reg_mapping_pll );
writeMMIORegList( ai, values, intern_reg_mapping_after_pll );
// un-reset FIFO to access timing table
OUTREG( ai->regs, RADEON_TV_MASTER_CNTL,
orig_tv_master_cntl |
RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST |
RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST |
RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST );
Radeon_ImpacTVwriteHorTimingTable( ai, Radeon_InternalTVOutWriteFIFO, values, true );
Radeon_ImpacTVwriteVertTimingTable( ai, Radeon_InternalTVOutWriteFIFO, values );
snooze( 50000 );
values->tv_master_cntl = orig_tv_master_cntl;
writeMMIORegList( ai, values, intern_reg_mapping_finish );
}
// read list of MM I/O registers
static void readMMIORegList(
accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
{
vuint8 *regs = ai->regs;
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
*(uint32 *)((char *)(values) + mapping->offset) =
INREG( regs, mapping->address );
/*SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );*/
}
//snooze( 1000000 );
}
// read list of PLL registers
static void readPLLRegList(
accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
{
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
*(uint32 *)((char *)(values) + mapping->offset) =
Radeon_INPLL( ai->regs, ai->si->asic, mapping->address );
/*SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );*/
}
//snooze( 1000000 );
}
// read TV-Out registers
void Radeon_InternalTVOutReadRegisters(
accelerator_info *ai, impactv_regs *values )
{
readMMIORegList( ai, values, intern_reg_mapping_before_pll );
readPLLRegList( ai, values, intern_reg_mapping_pll );
readMMIORegList( ai, values, intern_reg_mapping_after_pll );
readMMIORegList( ai, values, intern_reg_mapping_finish );
//snooze( 1000000 );
}
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002,03 Thomas Kurschel
Copyright (c) 2002-2004 Thomas Kurschel
Part of Radeon accelerant
@@ -17,6 +17,8 @@
#include "ddc_regs.h"
#include "gpiopad_regs.h"
#include "pll_access.h"
#include "theatre_regs.h"
#include "set_mode.h"
#include "ddc.h"
#include <malloc.h>
@@ -60,38 +62,6 @@ static status_t set_signals( void *cookie, int clk, int data )
}
/*
// check whether there is a monitor by talking to him via DDC2
// ddc_port - register to use for DDC2 communication
static bool Radeon_DetectMonitorViaDDC( accelerator_info *ai, uint32 ddc_port )
{
i2c_bus bus;
ddc_port_info info;
edid1_info edid;
void *vdif;
size_t vdif_len;
status_t res;
info.ai = ai;
info.port = ddc_port;
bus.cookie = &info;
bus.set_signals = &set_signals;
bus.get_signals = &get_signals;
res = ddc2_read_edid1( &bus, &edid, &vdif, &vdif_len );
if( res != B_OK )
return false;
if( vdif != NULL )
free( vdif );
SHOW_INFO( 2, "Found monitor on DDC port 0x%04x", ddc_port );
return true;
}
*/
// read EDID information from monitor
// ddc_port - register to use for DDC2 communication
bool Radeon_ReadEDID( accelerator_info *ai, uint32 ddc_port, edid1_info *edid )
@@ -117,7 +87,7 @@ bool Radeon_ReadEDID( accelerator_info *ai, uint32 ddc_port, edid1_info *edid )
if( vdif != NULL )
free( vdif );
return true;
}
@@ -260,7 +230,10 @@ static bool Radeon_DetectTVCRT_R300( accelerator_info *ai )
{
vuint8 *regs = ai->regs;
uint32 old_crtc2_gen_cntl, old_tv_dac_cntl, old_dac_cntl2, tmp;
uint32 old_radeon_gpiopad_a;
bool found;
old_radeon_gpiopad_a = INREG( regs, RADEON_GPIOPAD_A );
// whatever these flags mean - let's pray they won't get changed
OUTREGP( regs, RADEON_GPIOPAD_EN, 1, ~1 );
@@ -307,10 +280,12 @@ static bool Radeon_DetectTVCRT_R300( accelerator_info *ai )
found = (INREG( regs, RADEON_DAC_CNTL2 ) & RADEON_DAC2_CMP_OUT_B) != 0;
// clean up the mess
OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 );
OUTREG( regs, RADEON_DAC_EXT_CNTL, 0 );
OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl );
OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl );
OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 );
OUTREG( regs, RADEON_DAC_EXT_CNTL, 0 );
OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl );
OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl );
OUTREGP( regs, RADEON_GPIOPAD_A, old_radeon_gpiopad_a, ~1 );
return found;
}
@@ -323,6 +298,9 @@ static bool Radeon_DetectTVCRT( accelerator_info *ai )
case rt_r100:
case rt_m6:
case rt_m7:
case rt_m9:
case rt_m9plus:
case rt_m10:
// original Radeons have pure DVI only and mobility chips
// have no DVI connector
// TBD: can they have a docking station for CRT on TV-DAC?
@@ -332,6 +310,9 @@ static bool Radeon_DetectTVCRT( accelerator_info *ai )
case rt_rv200:
case rt_rv250:
case rt_rv280:
// IGP is guessed
case rt_rs100:
case rt_rs200:
return Radeon_DetectTVCRT_RV200( ai );
case rt_r300:
@@ -342,9 +323,10 @@ static bool Radeon_DetectTVCRT( accelerator_info *ai )
case rt_r360:
return Radeon_DetectTVCRT_R300( ai );
default:
// don't know about IGP
;
case rt_r200:
// r200 has no built-in TV-out and thus no TV-DAC to use for
// second CRT
return dd_none;
}
return dd_none;
@@ -443,6 +425,9 @@ static display_device_e Radeon_DetectTV_R300( accelerator_info *ai )
vuint8 *regs = ai->regs;
display_device_e displays = dd_none;
uint32 tmp, old_dac_cntl2, old_crtc2_gen_cntl, old_dac_ext_cntl, old_tv_dac_cntl;
uint32 old_radeon_gpiopad_a;
old_radeon_gpiopad_a = INREG( regs, RADEON_GPIOPAD_A );
// whatever these flags mean - let's pray they won't get changed
OUTREGP( regs, RADEON_GPIOPAD_EN, 1, ~1 );
@@ -511,66 +496,214 @@ static display_device_e Radeon_DetectTV_R300( accelerator_info *ai )
OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl );
OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 );
// again the magic wire
// !if you uncomment this, TV-out gets disabled
//OUTREGP( regs, RADEON_GPIOPAD_A, 1, ~1 );
OUTREGP( regs, RADEON_GPIOPAD_A, old_radeon_gpiopad_a, ~1 );
return displays;
}
// save readout of TV detection comparators
static bool readTVDetect( accelerator_info *ai )
{
uint32 tmp;
int i;
bigtime_t start_time;
bool detect;
// make output constant
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL,
RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK );
// check detection result
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &tmp );
detect = (tmp & RADEON_TV_DAC_CNTL_CMPOUT) != 0;
//SHOW_FLOW( 2, "detect=%d", detect );
start_time = system_time();
do {
// wait for stable detect signal
for( i = 0; i < 5; ++i ) {
bool cur_detect;
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL,
RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK |
RADEON_TV_DAC_CNTL_NHOLD );
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL,
RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK );
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &tmp );
cur_detect = (tmp & RADEON_TV_DAC_CNTL_CMPOUT) != 0;
//SHOW_FLOW( 2, "cur_detect=%d", cur_detect );
if( cur_detect != detect )
break;
detect = cur_detect;
}
if( i == 5 ) {
//SHOW_FLOW( 2, "return %d", detect );
return detect;
}
// don't wait forever - give up after 1 second
} while( system_time() - start_time < 1000000 );
SHOW_FLOW0( 2, "timeout" );
return false;
}
// detect TV connected to external Theatre-Out
static display_device_e Radeon_DetectTV_Theatre( accelerator_info *ai )
{
uint32
old_tv_dac_cntl, old_pre_dac_mux_cntl, old_modulator_cntl1, old_master_cntl;
uint32
uv_adr, old_last_fifo_entry, old_mid_fifo_entry, last_fifo_addr;
display_device_e displays = dd_none;
if( ai->si->tv_chip != tc_external_rt1 )
return dd_none;
// save previous values (TV-Out may be running)
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &old_tv_dac_cntl );
// enable DAC and comparators
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL,
RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT |
RADEON_TV_DAC_CNTL_NHOLD | RADEON_TV_DAC_CNTL_NBLANK );
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, &old_pre_dac_mux_cntl );
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, &old_modulator_cntl1 );
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, &old_master_cntl );
// save output timing
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_UV_ADR, &uv_adr );
last_fifo_addr = (uv_adr & RADEON_TV_UV_ADR_MAX_UV_ADR_MASK) * 2 + 1;
old_last_fifo_entry = Radeon_TheatreReadFIFO( ai, last_fifo_addr );
old_mid_fifo_entry = Radeon_TheatreReadFIFO( ai, 0x18f );
Radeon_TheatreWriteFIFO( ai, last_fifo_addr, 0x20208 );
Radeon_TheatreWriteFIFO( ai, 0x18f, 0x3ff2608 );
// stop TV-Out to savely program it
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL,
RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST | RADEON_TV_MASTER_CNTL_TV_ASYNC_RST );
// set constant base level
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1,
(0x2c << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) |
(0x2c << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT) );
// enable output
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL,
RADEON_TV_MASTER_CNTL_TV_ASYNC_RST );
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL,
0 );
// set constant Composite output
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL,
RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN |
RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN |
(9 << RADEON_TV_PRE_DAC_MUX_CNTL_BLU_MX_SHIFT) |
(0xa8 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT) );
// check for S-Video connection
if( readTVDetect( ai )) {
SHOW_FLOW0( 2, "Composite-Out of Rage Theatre is connected" );
displays |= dd_ctv;
}
// enable output changes
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL,
RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK |
RADEON_TV_DAC_CNTL_NHOLD );
// set constant Y-output of S-Video adapter
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL,
RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN |
RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN |
(9 << RADEON_TV_PRE_DAC_MUX_CNTL_RED_MX_SHIFT) |
(0xa8 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT) );
// check for composite connection
if( readTVDetect( ai )) {
SHOW_FLOW0( 2, "S-Video-Out of Rage Theatre is connected" );
displays |= dd_stv;
}
// restore everything
Radeon_TheatreWriteFIFO( ai, last_fifo_addr, old_last_fifo_entry );
Radeon_TheatreWriteFIFO( ai, 0x18f, old_mid_fifo_entry );
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, old_master_cntl );
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, old_modulator_cntl1 );
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, old_pre_dac_mux_cntl );
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, old_tv_dac_cntl );
return displays;
}
// check whether there is a TV connected to TV-DAC
// returns bit set, i.e. there can be S-Video or composite or both
static display_device_e Radeon_DetectTV( accelerator_info *ai, bool tv_crt_found )
{
switch( ai->si->asic ) {
case rt_r100:
case rt_r200:
return Radeon_DetectTV_Theatre( ai );
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_m9:
case rt_rv280:
case rt_m9plus:
// IGP method is guessed
case rt_rs100:
case rt_rs200:
return Radeon_DetectTV_RV200( ai, tv_crt_found );
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_m10:
case rt_r350:
case rt_r360:
return Radeon_DetectTV_R300( ai );
default:
// don't know about IGP
;
}
return dd_none;
}
// read edid data of flat panel and setup its timing accordingly
static status_t Radeon_StoreFPEDID( accelerator_info *ai, edid1_info *edid )
// get native monitor timing, using Detailed Monitor Description
static void Radeon_FindFPTiming_DetailedMonitorDesc(
const edid1_info *edid, fp_info *fp, uint32 *max_hsize, uint32 *max_vsize )
{
fp_info *fp = &ai->si->flatpanels[0];
uint32 max_hsize, max_vsize;
int i;
SHOW_FLOW0( 2, "EDID data read from DVI port via DDC2:" );
edid_dump( edid );
// find detailed timing with maximum resolution
max_hsize = max_vsize = 0;
for( i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i ) {
if( edid->detailed_monitor[i].monitor_desc_type == edid1_is_detailed_timing ) {
edid1_detailed_timing *timing = &edid->detailed_monitor[i].data.detailed_timing;
const edid1_detailed_timing *timing = &edid->detailed_monitor[i].data.detailed_timing;
if( timing->h_size > max_hsize && timing->v_size > max_vsize ) {
SHOW_FLOW( 2, "Found DDC data for mode %dx%d",
(int)timing->h_active, (int)timing->v_active );
max_hsize = timing->h_active;
max_vsize = timing->v_active;
SHOW_FLOW( 2, "Found detailed timing for mode %dx%d in DDC data",
(int)timing->h_active, (int)timing->v_active );
if( timing->h_active > *max_hsize && timing->v_active > *max_vsize ) {
*max_hsize = timing->h_active;
*max_vsize = timing->v_active;
// copy it to timing specification
fp->panel_xres = timing->h_active;
@@ -588,9 +721,114 @@ static status_t Radeon_StoreFPEDID( accelerator_info *ai, edid1_info *edid )
}
}
}
}
if( max_hsize == 0 )
return B_ERROR;
// get native monitor timing, using Standard Timing table;
// this table doesn't contain the actual timing, so we try to find a
// appropriate VESA modes for the resolutions given in the table
static void Radeon_FindFPTiming_StandardTiming(
const edid1_info *edid, fp_info *fp, uint32 *max_hsize, uint32 *max_vsize )
{
int i;
for( i = 0; i < EDID1_NUM_STD_TIMING; ++i ) {
const edid1_std_timing *std_timing = &edid->std_timing[i];
int best_fit = -1;
int best_refresh_deviation = 10000;
int j;
if( std_timing->h_size <= 256 )
continue;
for( j = 0; j < (int)vesa_mode_list_count; ++j ) {
int refresh_rate, cur_refresh_deviation;
if( vesa_mode_list[j].h_display != std_timing->h_size ||
vesa_mode_list[j].v_display != std_timing->v_size )
continue;
// take pixel_clock times 1000 because is is in kHz
// further, take it times 1000 again, to get 1/1000 frames
// as refresh rate
refresh_rate = (int64)vesa_mode_list[j].pixel_clock * 1000*1000 /
(vesa_mode_list[j].h_total * vesa_mode_list[j].v_total);
// standard timing is in frames, so multiple by it to get 1/1000 frames
// result is scaled by 100 to get difference in percentage;
cur_refresh_deviation =
(100 * (refresh_rate - std_timing->refresh * 1000)) / refresh_rate;
if( cur_refresh_deviation < 0 )
cur_refresh_deviation = -cur_refresh_deviation;
// less then 1 percent difference is (hopefully) OK,
// if there are multiple, we take best one
// (if the screen is that picky, it should have defined an enhanced timing)
if( cur_refresh_deviation < 1 &&
cur_refresh_deviation < best_refresh_deviation )
{
best_fit = j;
best_refresh_deviation = cur_refresh_deviation;
}
}
if( best_fit < 0 ) {
SHOW_FLOW( 2, "Unsupported standard mode %dx%d@%dHz (not VESA)",
std_timing->h_size, std_timing->v_size, std_timing->refresh );
continue;
}
if( std_timing->h_size > *max_hsize && std_timing->h_size > *max_vsize ) {
const display_timing *timing = &vesa_mode_list[best_fit];
SHOW_FLOW( 2, "Found DDC data for standard mode %dx%d",
(int)timing->h_display, (int)timing->v_display );
*max_hsize = timing->h_display;
*max_vsize = timing->h_display;
// copy it to timing specification
fp->panel_xres = timing->h_display;
fp->h_blank = timing->h_total - timing->h_display;
fp->h_over_plus = timing->h_sync_start - timing->h_display;
fp->h_sync_width = timing->h_sync_end - timing->h_sync_start;
fp->panel_yres = timing->v_display;
fp->v_blank = timing->v_total - timing->v_display;
fp->v_over_plus = timing->v_sync_start - timing->v_display;
fp->v_sync_width = timing->v_sync_end - timing->v_sync_start;
fp->dot_clock = timing->pixel_clock;
}
}
}
// read edid data of flat panel and setup its timing accordingly
static status_t Radeon_StoreFPEDID( accelerator_info *ai, const edid1_info *edid )
{
fp_info *fp = &ai->si->flatpanels[0];
uint32 max_hsize, max_vsize;
SHOW_FLOW0( 2, "EDID data read from DVI port via DDC2:" );
edid_dump( edid );
// find detailed timing with maximum resolution
max_hsize = max_vsize = 0;
Radeon_FindFPTiming_DetailedMonitorDesc( edid, fp, &max_hsize, &max_vsize );
if( max_hsize == 0 ) {
SHOW_FLOW0( 2, "Timing is not explicitely defined in DDC - checking standard modes" );
Radeon_FindFPTiming_StandardTiming(
edid, fp, &max_hsize, &max_vsize );
if( max_hsize == 0 ) {
SHOW_FLOW0( 2, "Still found no valid native mode, disabling DVI" );
return B_ERROR;
}
}
SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d",
fp->panel_xres, fp->h_blank, fp->h_over_plus, fp->h_sync_width );
@@ -608,7 +846,11 @@ void Radeon_DetectDisplays( accelerator_info *ai )
{
shared_info *si = ai->si;
display_device_e displays = 0;
display_device_e controlled_displays = ai->vc->controlled_displays;
edid1_info edid;
// lock hardware so noone bothers us
Radeon_WaitForIdle( ai, true );
// mobile chips are for use in laptops - there must be a laptop panel
if( si->is_mobility )
@@ -636,8 +878,8 @@ void Radeon_DetectDisplays( accelerator_info *ai )
// must be the analog portion of DVI
// I'm not sure about Radeons with one CRTC - do they have DVI-I or DVI-D?
// anyway - if there are two CRTC, analog portion must be connected
// to TV-DAC, if there is one CRTC, it must be the normal VGA-DAC
if( si->num_heads > 1 ) {
// to TV-DAC; if there is one CRTC, it must be the normal VGA-DAC
if( si->num_crtc > 1 ) {
SHOW_FLOW0( 2, "Must be an analog monitor on DVI port" );
displays |= dd_tv_crt;
} else {
@@ -661,27 +903,30 @@ void Radeon_DetectDisplays( accelerator_info *ai )
// all versions have a standard VGA port
if( (displays & dd_crt) == 0 &&
(controlled_displays && dd_crt) != 0 &&
Radeon_DetectCRT( ai ))
displays |= dd_crt;
// check VGA signal routed to DVI port
// (the detection code checks whether there is hardware for that)
if( (displays & dd_tv_crt) == 0 &&
(controlled_displays && dd_tv_crt) != 0 &&
Radeon_DetectTVCRT( ai ))
displays |= dd_tv_crt;
// TV-Out doesn't work, so don't detect that
#if 0
// check TV-out connector
// (this is the only one where we cannot use DDC)
displays |= Radeon_DetectTV( ai, (displays & dd_tv_crt) != 0 );
#endif
if( (controlled_displays && (dd_ctv | dd_stv)) != 0 )
displays |= Radeon_DetectTV( ai, (displays & dd_tv_crt) != 0 );
SHOW_INFO( 0, "Detected monitors: 0x%x", displays );
displays &= controlled_displays;
// if no monitor found, we define to have a CRT connected to CRT-DAC
if( displays == 0 )
displays = dd_crt;
si->connected_displays = displays;
ai->vc->connected_displays = displays;
RELEASE_BEN( si->cp.lock );
}
+546 -130
View File
@@ -1,10 +1,13 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Copyright (c) 2002-04, Thomas Kurschel
Part of Radeon accelerant
CRTC <-> display routing
This stuff is highly ASIC dependant and is probably the most ASIC-specific
code of the entire project.
*/
#include "radeon_accelerant.h"
@@ -13,40 +16,56 @@
#include "fp_regs.h"
#include "crtc_regs.h"
#include "tv_out_regs.h"
#include "pll_regs.h"
#include "gpiopad_regs.h"
#include "pll_access.h"
#include "set_mode.h"
// read regs needed for display device routing
void Radeon_ReadMonitorRoutingRegs( accelerator_info *ai, physical_head *head,
port_regs *values )
void Radeon_ReadMonitorRoutingRegs(
accelerator_info *ai, routing_regs *values )
{
vuint8 *regs = ai->regs;
(void)head;
values->dac_cntl = INREG( regs, RADEON_DAC_CNTL );
values->dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 );
values->crtc_ext_cntl = INREG( regs, RADEON_CRTC_EXT_CNTL );
values->crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL );
values->disp_output_cntl = INREG( regs, RADEON_DISP_OUTPUT_CNTL );
values->pixclks_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL );
values->vclk_ecp_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL );
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
break;
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_rv280:
case rt_m9:
default:
case rt_rv280:
case rt_m9plus:
case rt_rs100:
case rt_rs200:
values->disp_hw_debug = INREG( regs, RADEON_DISP_HW_DEBUG );
break;
case rt_r200:
values->disp_tv_out_cntl = INREG( regs, RADEON_DISP_TV_OUT_CNTL );
break;
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_m10:
case rt_rv360:
case rt_r350:
case rt_r360:
values->gpiopad_a = INREG( regs, RADEON_GPIOPAD_A );
break;
case rt_r100:
break;
}
if( ai->si->asic > rt_r100 ) {
@@ -54,121 +73,365 @@ void Radeon_ReadMonitorRoutingRegs( accelerator_info *ai, physical_head *head,
values->tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL );
}
if( IS_INTERNAL_TV_OUT( ai->si->tv_chip ))
values->tv_master_cntl = INREG( regs, RADEON_TV_MASTER_CNTL );
values->fp_gen_cntl = INREG( regs, RADEON_FP_GEN_CNTL );
values->fp2_gen_cntl = INREG( regs, RADEON_FP2_GEN_CNTL );
}
// setup register contents to proper CRTC <-> display device mapping
void Radeon_CalcMonitorRouting( accelerator_info *ai, physical_head *head,
port_regs *values )
void Radeon_CalcMonitorRouting(
accelerator_info *ai, const impactv_params *tv_parameters, routing_regs *values )
{
display_device_e display_devices;
display_device_e display_devices[2], total_devices, controlled_devices;
display_devices = head->chosen_displays;
if( ai->vc->used_crtc[0] )
display_devices[0] = ai->si->crtc[0].chosen_displays;
else
display_devices[0] = dd_none;
if( ai->vc->used_crtc[1] )
display_devices[1] = ai->si->crtc[1].chosen_displays;
else
display_devices[1] = dd_none;
total_devices = display_devices[0] | display_devices[1];
controlled_devices = ai->vc->controlled_displays;
// enable 8 bit DAC
// (could be moved to boot initialization)
values->dac_cntl |=
RADEON_DAC_MASK_ALL | RADEON_DAC_VGA_ADR_EN | RADEON_DAC_8BIT_EN;
// enable frame buffer access and extended CRTC counter
// (again: something for boot init.)
values->crtc_ext_cntl =
RADEON_VGA_ATI_LINEAR | RADEON_XCRT_CNT_EN;
// set VGA signal style (not sure whether this affects
// CRTC1 or CRT-DAC, so we better always set it)
values->dac_cntl &= ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_BLANKING);
values->dac_cntl |= RADEON_DAC_RANGE_CNTL_PS2;
// disable all the magic CRTC shadowing
values->fp_gen_cntl &=
~(RADEON_FP_RMX_HVSYNC_CONTROL_EN |
RADEON_FP_DFP_SYNC_SEL |
RADEON_FP_CRT_SYNC_SEL |
RADEON_FP_CRTC_LOCK_8DOT |
RADEON_FP_USE_SHADOW_EN |
RADEON_FP_CRTC_USE_SHADOW_VEND |
RADEON_FP_CRT_SYNC_ALT);
values->fp_gen_cntl |=
RADEON_FP_CRTC_DONT_SHADOW_VPAR |
RADEON_FP_CRTC_DONT_SHADOW_HEND;
// route VGA-DAC
if( (display_devices & dd_crt) != 0 ) {
if( (total_devices & dd_crt) != 0 ) {
int crtc_idx = (display_devices[1] & dd_crt) != 0;
// the CRT_ON flag seems to directly affect the CRT-DAC, _not_ the CRTC1 signal
values->crtc_ext_cntl |= RADEON_CRTC_CRT_ON;
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
values->disp_output_cntl =
(values->disp_output_cntl & ~RADEON_DISP_DAC_SOURCE_MASK) |
(head->is_crtc2 ? RADEON_DISP_DAC_SOURCE_CRTC2 : 0);
break;
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_rv280:
case rt_m9:
default:
case rt_rv280:
case rt_m9plus:
case rt_rs100:
case rt_rs200:
values->dac_cntl2 &= ~RADEON_DAC_CLK_SEL_MASK;
values->dac_cntl2 |= head->is_crtc2 ? RADEON_DAC_CLK_SEL_CRTC2 : 0;
values->dac_cntl2 |= crtc_idx == 0 ? 0 : RADEON_DAC_CLK_SEL_CRTC2;
break;
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_m10:
case rt_rv360:
case rt_r350:
case rt_r360:
values->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK;
values->disp_output_cntl |=
(crtc_idx == 0 ? 0 : RADEON_DISP_DAC_SOURCE_CRTC2);
break;
case rt_r100:
break;
}
} else if( (controlled_devices & dd_crt) != 0 ) {
values->crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON;
}
if( (total_devices & (dd_tv_crt | dd_ctv | dd_stv)) != 0 ) {
// power down TV-DAC
// (but only if TV-Out _and_ TV-CRT is controlled by us)
// this will be undone if needed
values->tv_dac_cntl |=
RADEON_TV_DAC_CNTL_RDACPD |
RADEON_TV_DAC_CNTL_GDACPD |
RADEON_TV_DAC_CNTL_BDACPD;
}
// set CRT mode of TV-DAC if needed
if( (display_devices & dd_tv_crt) != 0 ) {
// TODO: this register doesn't exist on r200 as TV DAC is on
// external Rage Theatre
// (doesn't work on r200, but there is no TV-DAC used for CRT anyway)
if( (total_devices & dd_tv_crt) != 0 ) {
// enable CRT via TV-DAC (ignored if TV-DAC is in TV-Out mode)
values->crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON;
values->dac_cntl2 &= ~RADEON_DAC2_CLK_SEL_MASK;
values->dac_cntl2 |= RADEON_DAC2_CLK_SEL_CRT;
// enable TV-DAC
// enable TV-DAC and set PS2 signal level
values->tv_dac_cntl =
RADEON_TV_DAC_CNTL_NBLANK |
RADEON_TV_DAC_CNTL_NHOLD |
RADEON_TV_DAC_CNTL_STD_PS2;
RADEON_TV_DAC_CNTL_STD_PS2 |
(8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) |
(2 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT);
// at least r300 needs magic bit set to switch between TV-CRT and TV-Out
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_m10:
case rt_rv360:
case rt_r350:
case rt_r360:
values->gpiopad_a |= 1;
break;
default:
;
}
} else if( (controlled_devices & dd_tv_crt) != 0 ) {
values->crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON;
}
values->skip_tv_dac = false;
// disable forwarding data to TV-Out unit
// (will be enabled on demand later on)
if( (controlled_devices & (dd_ctv | dd_stv)) != 0 )
values->dac_cntl &= ~RADEON_DAC_TVO_EN;
// set TV mode of TV-DAC if needed
if( (display_devices & (dd_ctv | dd_stv)) != 0 ) {
if( (total_devices & (dd_ctv | dd_stv)) != 0 ) {
// see above
values->dac_cntl2 &= ~RADEON_DAC2_CLK_SEL_MASK;
values->dac_cntl2 |= RADEON_DAC2_CLK_SEL_TV;
}
// at least r300 needs magic bit set to switch between TV-CRT and TV-Out
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_m10:
case rt_r350:
case rt_r360:
values->gpiopad_a &= ~1;
break;
default:
;
}
// the TV-DAC itself is under control of the TV-Out code
values->skip_tv_dac = true;
if( !IS_INTERNAL_TV_OUT( ai->si->tv_chip )) {
// tell DAC to forward data to external chip
values->dac_cntl |= RADEON_DAC_TVO_EN;
// set Output Linear Transform Unit as source
// (TODO: is this unit initialized properly?)
// disable overlay sync (could be a good idea to enable it)
// set 8 BPP mode
values->disp_output_cntl &=
~(RADEON_DISP_TV_SOURCE |
RADEON_DISP_TV_MODE_MASK |
RADEON_DISP_TV_YG_DITH_EN |
RADEON_DISP_TV_CBB_CRR_DITH_EN |
RADEON_DISP_TV_BIT_WIDTH |
RADEON_DISP_TV_SYNC_MODE_MASK |
RADEON_DISP_TV_SYNC_COLOR_MASK);
// enable dithering
values->disp_output_cntl |=
RADEON_DISP_TV_YG_DITH_EN |
RADEON_DISP_TV_CBB_CRR_DITH_EN;
// set output data format
values->disp_output_cntl |= tv_parameters->mode888 ?
RADEON_DISP_TV_MODE_888 : RADEON_DISP_TV_MODE_565;
switch( ai->si->asic ) {
case rt_r200:
// disable downfiltering and scaling, set RGB mode,
// don't transmit overlay indicator;
// I don't really know whether this is a good choice
values->disp_tv_out_cntl &=
(RADEON_DISP_TV_OUT_YG_FILTER_MASK |
RADEON_DISP_TV_OUT_YG_SAMPLE |
RADEON_DISP_TV_OUT_CrR_FILTER_MASK |
RADEON_DISP_TV_OUT_CrR_SAMPLE |
RADEON_DISP_TV_OUT_CbB_FILTER_MASK |
RADEON_DISP_TV_OUT_CbB_SAMPLE |
RADEON_DISP_TV_SUBSAMPLE_CNTL_MASK |
RADEON_DISP_TV_H_DOWNSCALE |
RADEON_DISP_TV_COLOR_SPACE |
RADEON_DISP_TV_DITH_MODE |
RADEON_DISP_TV_DATA_ZERO_SEL |
RADEON_DISP_TV_CLKO_SEL |
RADEON_DISP_TV_CLKO_OUT_EN |
RADEON_DISP_TV_DOWNSCALE_CNTL);
// enable TVOCLKO (is this needed?)
values->disp_tv_out_cntl |= RADEON_DISP_TV_CLKO_OUT_EN;
break;
default:
;
}
}
} else if( (controlled_devices & (dd_ctv | dd_stv)) != 0 ) {
if( IS_INTERNAL_TV_OUT( ai->si->tv_chip )) {
// disable clock of TV-out units
values->tv_master_cntl =
RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST |
RADEON_TV_MASTER_CNTL_TVCLK_ALWAYS_ONb;
}
}
// choose CRTC for TV-DAC
if( (display_devices & (dd_tv_crt | dd_ctv | dd_stv)) != 0 ) {
if( (total_devices & (dd_tv_crt | dd_ctv | dd_stv)) != 0 ) {
int crtc_idx = (display_devices[1] & (dd_tv_crt | dd_ctv | dd_stv)) != 0;
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
// for r200, this register doesn not exist!?
// according to r300 spec, this is because TV-DAC is on external chip
values->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
values->disp_output_cntl |=
head->is_crtc2 ? RADEON_DISP_TVDAC_SOURCE_CRTC2 : 0;
break;
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_rv280:
case rt_m9:
default:
case rt_rv280:
case rt_m9plus:
case rt_rs100:
case rt_rs200:
values->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
values->disp_hw_debug |= head->is_crtc2 ? RADEON_CRT2_DISP1_SEL : 0;
// warning: meaning is wrong way around - 0 means crtc2, 1 means crtc1
values->disp_hw_debug |= crtc_idx == 0 ? RADEON_CRT2_DISP1_SEL : 0;
break;
case rt_r200:
// TV-Out data comes directly from CRTC (i.e. with Linear Transform Unit)
values->disp_output_cntl |= RADEON_DISP_TV_SOURCE;
// choose CRTC
values->disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC;
values->disp_tv_out_cntl |= crtc_idx == 0 ? 0 : RADEON_DISP_TV_PATH_SRC;
break;
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_m10:
case rt_rv360:
case rt_r350:
case rt_r360:
values->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
values->disp_output_cntl |=
crtc_idx == 0 ? 0 : RADEON_DISP_TVDAC_SOURCE_CRTC2;
break;
case rt_r100:
break;
}
}
// choose CRTC for flat panel
if( (display_devices & (dd_lvds | dd_dvi)) != 0 ) {
values->fp_gen_cntl |= head->is_crtc2 ? RADEON_FP_SEL_CRTC2 : 0;
// choose clock source for (internal) TV-out unit
if( (total_devices & (dd_ctv | dd_stv)) != 0 ) {
int crtc_idx = (display_devices[1] & (dd_ctv | dd_stv)) != 0;
values->pixclks_cntl &= ~RADEON_PIXCLK_TV_SRC_SEL_MASK;
values->pixclks_cntl |= crtc_idx == 0 ?
RADEON_PIXCLK_TV_SRC_SEL_PIXCLK : RADEON_PIXCLK_TV_SRC_SEL_PIX2CLK;
}
// enable/disable RMX for crtc1
// choose CRTC clock source;
// normally, CRTC1 uses PLL1 and CRTC2 uses PLL2, but if an external TV-Out
// chip is used, the clock is retrieved from this chip to stay in perfect sync
if( (display_devices[0] & (dd_ctv | dd_stv)) != 0
&& !IS_INTERNAL_TV_OUT( ai->si->tv_chip ))
{
// select BYTCLK input pin as pixel src
values->vclk_ecp_cntl &=
~(RADEON_VCLK_ECP_CNTL_BYTE_CLK_POST_DIV_MASK | RADEON_VCLK_SRC_SEL_MASK);
values->vclk_ecp_cntl |= RADEON_VCLK_SRC_BYTE_CLK;
values->vclk_ecp_cntl |= 0 << RADEON_VCLK_ECP_CNTL_BYTE_CLK_POST_DIV_SHIFT;
// disable clock if pixel format in CRTC_GEN_CNTL is zero;
// disable (DAC?) during blank
values->vclk_ecp_cntl |= RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb;
} else {
// select PLL as pixel clock
values->vclk_ecp_cntl &= ~RADEON_VCLK_SRC_SEL_MASK;
values->vclk_ecp_cntl |= RADEON_VCLK_SRC_PPLL_CLK;
// disable clock if pixel format in CRTC_GEN_CNTL is zero
values->vclk_ecp_cntl |= RADEON_PIXCLK_ALWAYS_ONb;
}
values->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK;
if( (display_devices[1] & (dd_ctv | dd_stv)) != 0
&& !IS_INTERNAL_TV_OUT( ai->si->tv_chip ))
{
// r200 spec misses everything regarding second CRTC, so
// this is guessing
values->pixclks_cntl |= 2;
} else
values->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLL_CLK;
// choose CRTC for flat panel
if( (total_devices & (dd_lvds | dd_dvi)) != 0 ) {
int crtc_idx = (display_devices[1] & (dd_lvds | dd_dvi)) != 0;
values->fp_gen_cntl &= ~RADEON_FP_SEL_CRTC2;
values->fp_gen_cntl |= crtc_idx == 0 ? 0 : RADEON_FP_SEL_CRTC2;
}
// enable/disable RMX for crtc1 if there is a flat panel
// (TODO: this doesn't seem to work)
// !!! makes trouble on Radeon 9200 Mobility !??
/*
if( !head->is_crtc2 ) {
// use RMX if there is a flat panel
if( (display_devices & (dd_lvds | dd_dvi)) != 0 ) {
values->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK;
values->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_RMX;
}
}*/
if( (display_devices[1] & (dd_lvds | dd_dvi)) != 0 ) {
values->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK;
values->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_RMX;
}
// choose CRTC for secondary flat panel
if( (display_devices & dd_dvi_ext) != 0 ) {
if( (total_devices & dd_dvi_ext) != 0 ) {
int crtc_idx = (display_devices[1] & (dd_dvi_ext)) != 0;
// TODO: this list looks a bit magic/wrong for me; I reckon ATI moved the
// bit starting with ASIC xxx, but I have no specs to verify that
switch( ai->si->asic ) {
@@ -176,126 +439,279 @@ void Radeon_CalcMonitorRouting( accelerator_info *ai, physical_head *head,
case rt_r300:
case rt_r350:
case rt_rv350:
case rt_m10:
values->fp2_gen_cntl &= ~RADEON_FP2_SOURCE_SEL_CRTC2;
values->fp2_gen_cntl |=
head->is_crtc2 ? RADEON_FP2_SOURCE_SEL_CRTC2 : 0;
crtc_idx == 0 ? 0 : RADEON_FP2_SOURCE_SEL_CRTC2;
break;
default:
values->fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2;
values->fp2_gen_cntl |=
head->is_crtc2 ? RADEON_FP2_SRC_SEL_CRTC2 : 0;
crtc_idx == 0 ? 0 : RADEON_FP2_SRC_SEL_CRTC2;
}
}
// we don't set source of TV-OUT unit - it's done in the tv-out code
}
void Radeon_ProgramMonitorRouting( accelerator_info *ai, physical_head *head, port_regs *values )
void Radeon_ProgramMonitorRouting(
accelerator_info *ai, routing_regs *values )
{
vuint8 *regs = ai->regs;
(void)head;
OUTREG( regs, RADEON_DAC_CNTL, values->dac_cntl );
OUTREG( regs, RADEON_DAC_CNTL2, values->dac_cntl2 );
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, values->crtc_ext_cntl,
~RADEON_CRTC_CRT_ON );
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, values->crtc2_gen_cntl,
~RADEON_CRTC2_CRT2_ON );
OUTREG( regs, RADEON_DISP_OUTPUT_CNTL, values->disp_output_cntl );
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
break;
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_rv280:
case rt_m9:
default:
case rt_rv280:
case rt_m9plus:
case rt_rs100:
case rt_rs200:
OUTREG( regs, RADEON_DISP_HW_DEBUG, values->disp_hw_debug );
break;
case rt_r200:
OUTREG( regs, RADEON_DISP_TV_OUT_CNTL, values->disp_tv_out_cntl );
break;
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_m10:
case rt_rv360:
case rt_r350:
case rt_r360:
OUTREGP( regs, RADEON_GPIOPAD_A, values->gpiopad_a, ~1 );
break;
case rt_r100:
break;
}
if( ai->si->asic > rt_r100 ) {
// register introduced after R100
OUTREG( regs, RADEON_TV_DAC_CNTL, values->tv_dac_cntl );
// register introduced after R100;
// only set it when necessary (more precisely: if TV-Out is used,
// this register is set by the TV-Out code)
if( !values->skip_tv_dac )
OUTREG( regs, RADEON_TV_DAC_CNTL, values->tv_dac_cntl );
}
OUTREG( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl );
OUTREG( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl );
if( IS_INTERNAL_TV_OUT( ai->si->tv_chip ))
OUTREG( regs, RADEON_TV_MASTER_CNTL, values->tv_master_cntl );
OUTREGP( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl, ~(
RADEON_FP_SEL_CRTC2 |
RADEON_FP_RMX_HVSYNC_CONTROL_EN |
RADEON_FP_DFP_SYNC_SEL |
RADEON_FP_CRT_SYNC_SEL |
RADEON_FP_CRTC_LOCK_8DOT |
RADEON_FP_USE_SHADOW_EN |
RADEON_FP_CRTC_USE_SHADOW_VEND |
RADEON_FP_CRT_SYNC_ALT |
RADEON_FP_CRTC_DONT_SHADOW_VPAR |
RADEON_FP_CRTC_DONT_SHADOW_HEND ));
OUTREGP( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl,
~(RADEON_FP2_SOURCE_SEL_CRTC2 | RADEON_FP2_SRC_SEL_CRTC2 ));
if( ai->vc->used_crtc[0] ) {
Radeon_OUTPLLP( ai->regs, ai->si->asic,
RADEON_VCLK_ECP_CNTL, values->vclk_ecp_cntl,
~RADEON_VCLK_SRC_SEL_MASK );
}
if( ai->vc->used_crtc[1] ) {
Radeon_OUTPLLP( ai->regs, ai->si->asic,
RADEON_PIXCLKS_CNTL, values->pixclks_cntl,
~RADEON_PIX2CLK_SRC_SEL_MASK );
}
Radeon_OUTPLLP( ai->regs, ai->si->asic,
RADEON_PIXCLKS_CNTL, values->pixclks_cntl,
~RADEON_PIXCLK_TV_SRC_SEL_MASK );
// enable/disable CRTC1
if( ai->vc->assigned_crtc[0] ) {
uint32 crtc_gen_cntl;
crtc_gen_cntl = INREG( regs, RADEON_CRTC_GEN_CNTL );
if( ai->vc->used_crtc[0] ) {
crtc_gen_cntl |= RADEON_CRTC_EN;
} else {
crtc_gen_cntl &= ~RADEON_CRTC_EN;
crtc_gen_cntl &= ~RADEON_CRTC_PIX_WIDTH_MASK;
}
OUTREGP( regs, RADEON_CRTC_GEN_CNTL, crtc_gen_cntl,
~(RADEON_CRTC_PIX_WIDTH_MASK | RADEON_CRTC_EN) );
}
// enable/disable CRTC2
if( ai->vc->assigned_crtc[1] ) {
uint32 crtc2_gen_cntl;
crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL );
if( ai->vc->used_crtc[1] ) {
crtc2_gen_cntl |= RADEON_CRTC2_EN;
} else {
crtc2_gen_cntl &= ~RADEON_CRTC2_EN;
crtc2_gen_cntl &= ~RADEON_CRTC2_PIX_WIDTH_MASK;
}
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl,
~(RADEON_CRTC2_PIX_WIDTH_MASK | RADEON_CRTC2_EN) );
}
// XFree says that crtc_ext_cntl must be restored after CRTC2 in dual-screen mode
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, values->crtc_ext_cntl,
RADEON_CRTC_VSYNC_DIS |
RADEON_CRTC_HSYNC_DIS |
RADEON_CRTC_DISPLAY_DIS );
}
// Setup sensible default monitor routing
// whished_num_heads - number of independant heads current display mode would need
void Radeon_SetupDefaultMonitorRouting( accelerator_info *ai, int whished_num_heads )
// internal version of SetupDefaultMonitorRouting;
// input and output are written to local variables
void assignDefaultMonitorRoute(
accelerator_info *ai,
display_device_e display_devices, int whished_num_heads, bool use_laptop_panel,
display_device_e *crtc1, display_device_e *crtc2 )
{
virtual_card *vc = ai->vc;
display_device_e crtc1_displays = 0, crtc2_displays = 0;
display_device_e display_devices = ai->si->connected_displays;
SHOW_FLOW( 2, "display_devices=%x, whished_num_heads=%d",
display_devices, whished_num_heads );
// restrict to allowed devices
display_devices &= ai->vc->controlled_displays;
// if CRTC1 is not ours, we cannot use flat panels
if( !ai->vc->assigned_crtc[0] ) {
display_devices &= ~(dd_lvds | dd_dvi);
}
SHOW_FLOW( 2, "after restriction: %x", display_devices );
// flat panels get always connected to CRTC1 because its RMX unit
if( (display_devices & dd_lvds) != 0 ) {
// don't enable Laptop panel if display mode needs one head only
// and there is a CRT connected (showing the same on both panel and
// CRT doesn't make much sense)
if( !(whished_num_heads == 1 && (display_devices & (dd_crt | dd_tv_crt)) != 0 ))
// if user requests it, laptop panels are always used
if( use_laptop_panel ) {
crtc1_displays |= dd_lvds;
} else {
// if he doesn't request it, we try to not use it
display_device_e tmp_crtc1, tmp_crtc2;
int effective_num_heads;
// determine routing with laptop panel ignored
assignDefaultMonitorRoute( ai, display_devices & ~dd_lvds,
whished_num_heads, use_laptop_panel, &tmp_crtc1, &tmp_crtc2 );
effective_num_heads = (tmp_crtc1 != 0) + (tmp_crtc2 != 0);
// only use laptop panel if we cannot satisfy the requested
// number of heads without it
if( effective_num_heads < whished_num_heads )
crtc1_displays |= dd_lvds;
}
} else if( (display_devices & dd_dvi) != 0 )
crtc1_displays |= dd_dvi;
// TV-Out gets always connected to crtc2...
if( (display_devices & dd_stv) != 0 )
crtc2_displays |= dd_stv;
else if( (display_devices & dd_stv) != 0 )
else if( (display_devices & dd_ctv) != 0 )
crtc2_displays |= dd_ctv;
// ...but if there is no crtc2, they win on crtc1;
// if the user connects both a flat panel and a TV, he certainly wants to use the TV
if( ai->si->num_heads == 1 && crtc2_displays != 0 )
// if the user connects both a flat panel and a TV, he usually
// wants to use the TV
if( !vc->assigned_crtc[1] && crtc2_displays != 0 ) {
crtc1_displays = crtc2_displays;
crtc2_displays = dd_none;
}
// if TV-Out is used, the DAC cannot drive a CRT at the same time
if( (display_devices & (dd_stv | dd_ctv)) != 0 )
// if internal TV-Out is used, the DAC cannot drive a CRT at the same time
if( IS_INTERNAL_TV_OUT( ai->si->tv_chip ) && (display_devices & (dd_stv | dd_ctv)) != 0 )
display_devices &= ~dd_tv_crt;
// CRT on CRT-DAC gets any spare CRTC;
// if there is none, it can share CRTC with TV-Out
// if there is none, it can share CRTC with TV-Out;
// this sharing may be dangerous as TV-Out uses strange timings, so
// we should perhaps forbid sharing
if( (display_devices & dd_crt) != 0 ) {
if( crtc1_displays == 0 )
if( crtc1_displays == 0 && vc->assigned_crtc[0] )
crtc1_displays |= dd_crt;
else if( ai->si->num_heads > 1 && crtc2_displays == 0 )
else if( ai->si->num_crtc > 1 && crtc2_displays == 0 && vc->assigned_crtc[1] )
crtc2_displays |= dd_crt;
else if( (crtc1_displays & ~(dd_stv | dd_ctv)) == 0 )
else if( (crtc1_displays & ~(dd_stv | dd_ctv)) == 0 && vc->assigned_crtc[0] )
crtc1_displays |= dd_crt;
else if( ai->si->num_heads > 1 && (crtc2_displays & ~(dd_stv | dd_ctv)) == 0 )
else if( ai->si->num_crtc > 1 && (crtc2_displays & ~(dd_stv | dd_ctv)) == 0 && vc->assigned_crtc[1] )
crtc2_displays |= dd_crt;
}
// same applies to CRT on TV-DAC;
// if we cannot find a CRTC, we could clone the content of the CRT-DAC,
// but I doubt that you really want two CRTs showing the same
if( (display_devices & dd_tv_crt) != 0 &&
(display_devices & (dd_ctv | dd_stv)) == 0 )
{
if( crtc1_displays == 0 )
if( (display_devices & dd_tv_crt) != 0 ) {
if( crtc1_displays == 0 && vc->assigned_crtc[0] )
crtc1_displays |= dd_tv_crt;
else if( ai->si->num_heads > 1 && crtc2_displays == 0 )
else if( ai->si->num_crtc > 1 && crtc2_displays == 0 && vc->assigned_crtc[1] )
crtc2_displays |= dd_tv_crt;
else if( (crtc1_displays & ~(dd_stv | dd_ctv)) == 0 )
else if( (crtc1_displays & ~(dd_stv | dd_ctv)) == 0 && vc->assigned_crtc[0] )
crtc1_displays |= dd_tv_crt;
else if( ai->si->num_heads > 1 && (crtc2_displays & ~(dd_stv | dd_ctv)) == 0 )
else if( ai->si->num_crtc > 1 && (crtc2_displays & ~(dd_stv | dd_ctv)) == 0 && vc->assigned_crtc[1] )
crtc2_displays |= dd_tv_crt;
}
//crtc1_displays = dd_stv | dd_crt;
//crtc2_displays = 0;
SHOW_FLOW( 3, "CRTC1: 0x%x, CRTC2: 0x%x", crtc1_displays, crtc2_displays );
SHOW_FLOW( 2, "CRTC1: 0x%x, CRTC2: 0x%x", crtc1_displays, crtc2_displays );
ai->si->heads[0].chosen_displays = crtc1_displays;
ai->si->heads[1].chosen_displays = crtc2_displays;
*crtc1 = crtc1_displays;
*crtc2 = crtc2_displays;
}
// Setup sensible default monitor routing
// whished_num_heads - number of independant heads current display mode would need
// use_laptop_panel - if true, always use laptop panel
void Radeon_SetupDefaultMonitorRouting(
accelerator_info *ai, int whished_num_heads, bool use_laptop_panel )
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
display_device_e display_devices = vc->connected_displays;
SHOW_FLOW( 2, "display_devices=%x, whished_num_heads=%d, use_laptop_panel=%d",
display_devices, whished_num_heads, use_laptop_panel );
// ignore TV if standard is set to "off"
if( vc->tv_standard == ts_off )
display_devices &= ~(dd_ctv | dd_stv);
assignDefaultMonitorRoute(
ai, display_devices, whished_num_heads, use_laptop_panel,
&si->crtc[0].chosen_displays, &si->crtc[1].chosen_displays );
/* si->crtc[0].chosen_displays = dd_none;
si->crtc[1].chosen_displays = dd_tv_crt;*/
/*vc->used_crtc[0] = si->crtc[0].chosen_displays != dd_none;
vc->used_crtc[1] = si->crtc[1].chosen_displays != dd_none;*/
SHOW_FLOW( 2, "num_crtc: %d, CRTC1 (%s): 0x%x, CRTC2 (%s): 0x%x",
si->num_crtc,
vc->assigned_crtc[0] ? "assigned" : "not assigned", si->crtc[0].chosen_displays,
vc->assigned_crtc[0] ? "assigned" : "not assigned", si->crtc[1].chosen_displays );
}
+116 -66
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
@@ -15,33 +15,15 @@
// transform official mode to internal, multi-screen mode enhanced mode
void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode )
{
mode->timing.flags &= ~RADEON_MODE_MASK;
(void)vc;
switch( vc->wanted_multi_mode ) {
case mm_mirror:
mode->timing.flags |= RADEON_MODE_MIRROR;
break;
case mm_clone:
mode->timing.flags |= RADEON_MODE_CLONE;
break;
case mm_combine:
mode->timing.flags |= RADEON_MODE_COMBINE;
break;
case mm_none:
default:
}
mode->timing.flags &= ~RADEON_MODE_MASK;
// combine mode is used if virtual area is twice as visible area
// and if scrolling is enabled; if combining is impossible, use
// cloning instead
if( (mode->flags & B_SCROLL) == 0 ) {
if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE ) {
SHOW_FLOW0( 3, "This isn't a combine mode, falling back to clone" );
mode->timing.flags &= ~RADEON_MODE_MASK;
mode->timing.flags |= RADEON_MODE_CLONE;
}
if( (mode->flags & B_SCROLL) == 0 )
return;
}
SHOW_FLOW0( 3, "possibly combine mode" );
@@ -51,20 +33,19 @@ void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode )
mode->timing.flags &= ~RADEON_MODE_POSITION_MASK;
if( mode->virtual_width == 2 * mode->timing.h_display ) {
SHOW_FLOW0( 3, "horizontal combine mode" );
SHOW_FLOW0( 2, "horizontal combine mode" );
mode->timing.flags |= RADEON_MODE_POSITION_HORIZONTAL;
mode->timing.flags &= ~RADEON_MODE_MASK;
mode->timing.flags |= RADEON_MODE_COMBINE;
} else if( mode->virtual_height == 2 * mode->timing.v_display ) {
SHOW_FLOW0( 3, "vertical combine mode" );
SHOW_FLOW0( 2, "vertical combine mode" );
mode->timing.flags |= RADEON_MODE_POSITION_VERTICAL;
mode->timing.flags &= ~RADEON_MODE_MASK;
mode->timing.flags |= RADEON_MODE_COMBINE;
} else {
// ups, this isn't really a combine mode - restore flags
SHOW_FLOW0( 3, "wasn't really a combine mode" );
SHOW_FLOW0( 2, "wasn't really a combine mode" );
mode->timing.flags &= ~RADEON_MODE_MASK;
mode->timing.flags |= RADEON_MODE_CLONE;
mode->flags |= B_SCROLL;
}
}
@@ -74,11 +55,13 @@ void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mo
{
// if there is no second port or no second monitor connected,
// fall back to standard mode
if( vc->num_heads == 1 ||
(si->heads[vc->heads[0].physical_head].chosen_displays == dd_none ||
si->heads[vc->heads[1].physical_head].chosen_displays == dd_none) )
{
SHOW_FLOW0( 3, "only one monitor - disabling any multi-mon mode" );
int num_usable_crtcs = vc->assigned_crtc[0] && si->crtc[0].chosen_displays != dd_none;
if( si->num_crtc > 1 )
num_usable_crtcs += vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none;
if( num_usable_crtcs < 2 ) {
SHOW_FLOW0( 2, "only one monitor - disabling any multi-mon mode" );
// restore flags if combine mode is selected
if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
mode->flags |= B_SCROLL;
@@ -101,24 +84,28 @@ void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode )
// initialize multi-screen mode dependant variables
void Radeon_InitMultiModeVars( virtual_card *vc, display_mode *mode )
void Radeon_InitMultiModeVars(
accelerator_info *ai, display_mode *mode )
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
uint32 x, y;
// setup single-screen mode
vc->eff_width = mode->timing.h_display;
vc->eff_height = mode->timing.v_display;
vc->heads[0].rel_x = 0;
vc->heads[0].rel_y = 0;
if( vc->used_crtc[0] ) {
si->crtc[0].rel_x = 0;
si->crtc[0].rel_y = 0;
}
if( vc->used_crtc[1] ) {
si->crtc[1].rel_x = 0;
si->crtc[1].rel_y = 0;
}
switch( mode->timing.flags & RADEON_MODE_MASK ) {
case RADEON_MODE_CLONE:
// in clone mode, ports are independant but show the same
vc->heads[1].rel_x = 0;
vc->heads[1].rel_y = 0;
break;
case RADEON_MODE_COMBINE:
// detect where second screen must be located and
// adapt total visible area accordingly
@@ -134,26 +121,27 @@ void Radeon_InitMultiModeVars( virtual_card *vc, display_mode *mode )
SHOW_FLOW( 3, "relative position of second screen: %d, %d", x, y );
vc->heads[1].rel_x = 0;
vc->heads[1].rel_y = 0;
// set relative offset
if( !vc->swap_displays ) {
vc->heads[1].rel_x = x;
vc->heads[1].rel_y = y;
si->crtc[1].rel_x = x;
si->crtc[1].rel_y = y;
} else {
vc->heads[0].rel_x = x;
vc->heads[0].rel_y = y;
si->crtc[0].rel_x = x;
si->crtc[0].rel_y = y;
}
break;
case RADEON_MODE_STANDARD:
case RADEON_MODE_MIRROR:
default:
// else, ports are independant but show the same
break;
}
}
// mapping of internal TV standard code to public TV standard code
static const uint32 private2be[] = {
0, 1, 3, 4, 103, 3/* PAL SCART - no public id, so I use PAL BDGHI */, 102 };
// check and execute tunnel settings command
status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
const display_mode *low, const display_mode *high, bool *isTunneled )
@@ -185,29 +173,91 @@ status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
*isTunneled = true;
/*SHOW_FLOW( 1, "tunnel access code=%d, command=%d",
mode->h_display_start, mode->v_display_start );*/
switch( mode->h_display_start ) {
case ms_swap:
if( mode->v_display_start != 0 )
vc->swap_displays = mode->timing.flags != 0;
else
switch( mode->v_display_start ) {
case 0:
mode->timing.flags = vc->swap_displays;
return B_OK;
// write settings instantly
Radeon_WriteSettings( vc );
return B_OK;
case 1:
vc->swap_displays = mode->timing.flags != 0;
vc->enforce_mode_change = true;
// write settings instantly
Radeon_WriteSettings( vc );
return B_OK;
}
break;
/* case ms_overlay_port:
if( mode->v_display_start != 0 )
vc->whished_overlay_port = mode->timing.flags;
else
mode->timing.flags = vc->whished_overlay_port;
case ms_use_laptop_panel:
// we must refuse this setting if there is no laptop panel;
// else, the preferences dialog would show this (useless) option
if( (vc->connected_displays & dd_lvds) == 0 )
return B_ERROR;
Radeon_WriteSettings( vc );
return B_OK;*/
switch( mode->v_display_start ) {
case 0:
mode->timing.flags = vc->use_laptop_panel;
//SHOW_FLOW( 1, "get use_laptop_panel settings (%d)", mode->timing.flags );
return B_OK;
case 1:
vc->use_laptop_panel = mode->timing.flags != 0;
//SHOW_FLOW( 1, "set use_laptop_panel settings (%d)", vc->use_laptop_panel );
vc->enforce_mode_change = true;
Radeon_WriteSettings( vc );
return B_OK;
}
break;
default:
return B_BAD_INDEX;
case ms_tv_standard:
switch( mode->v_display_start ) {
case 0:
mode->timing.flags = private2be[vc->tv_standard];
/*SHOW_FLOW( 1, "read tv_standard (internal %d, public %d)",
vc->tv_standard, mode->timing.flags );*/
return B_OK;
case 1:
switch( mode->timing.flags ) {
case 0: vc->tv_standard = ts_off; break;
case 1: vc->tv_standard = ts_ntsc; break;
case 2: break; // ntsc j
case 3: vc->tv_standard = ts_pal_bdghi; break;
case 4: vc->tv_standard = ts_pal_m; break;
case 5: break; // pal n
case 6: break; // secam - I reckon not supported by hardware
case 101: break; // ntsc 443
case 102: vc->tv_standard = ts_pal_60; break;
case 103: vc->tv_standard = ts_pal_nc; break;
}
SHOW_FLOW( 1, "set tv_standard (internal %d, public %d)",
vc->tv_standard, mode->timing.flags );
vc->enforce_mode_change = true;
Radeon_WriteSettings( vc );
return B_OK;
case 2: {
uint32 idx = mode->timing.flags;
// we limit it explicetely to NTSC and PAL as all other
// modes are not fully implemented
if( idx < sizeof( private2be ) / sizeof( private2be[0] ) &&
idx < 3 ) {
mode->timing.flags = private2be[idx];
return B_OK;
} else
return B_ERROR;
}
}
}
return B_ERROR;
}
@@ -216,13 +266,13 @@ bool Radeon_NeedsSecondPort( display_mode *mode )
{
switch( mode->timing.flags & RADEON_MODE_MASK ) {
case RADEON_MODE_COMBINE:
case RADEON_MODE_CLONE:
return true;
default:
return false;
}
}
// return number of ports showing differents parts of frame buffer
bool Radeon_DifferentPorts( display_mode *mode )
{
+67 -59
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
@@ -51,7 +51,8 @@ static struct {
// setup overlay unit before first use
void Radeon_InitOverlay( accelerator_info *ai, physical_head *head )
void Radeon_InitOverlay(
accelerator_info *ai, int crtc_idx )
{
vuint8 *regs = ai->regs;
shared_info *si = ai->si;
@@ -93,7 +94,7 @@ void Radeon_InitOverlay( accelerator_info *ai, physical_head *head )
// overlay unit can only handle up to 175 MHz, if pixel clock is higher,
// only every second pixel is handled
if( head->mode.timing.pixel_clock < 175000 )
if( si->crtc[crtc_idx].mode.timing.pixel_clock < 175000 )
ecp_div = 0;
else
ecp_div = 1;
@@ -101,7 +102,7 @@ void Radeon_InitOverlay( accelerator_info *ai, physical_head *head )
Radeon_OUTPLLP( regs, si->asic, RADEON_VCLK_ECP_CNTL,
ecp_div << RADEON_ECP_DIV_SHIFT, ~RADEON_ECP_DIV_MASK );
si->active_overlay.head = si->pending_overlay.head;
si->active_overlay.crtc_idx = si->pending_overlay.crtc_idx;
// invalidate active colour space
si->active_overlay.ob.space = -1;
@@ -140,7 +141,8 @@ space_transform trans_rgb =
// set overlay colour space transformation matrix
static void Radeon_SetTransform( accelerator_info *ai,
static void Radeon_SetTransform(
accelerator_info *ai,
float bright,
float cont,
float sat,
@@ -263,7 +265,8 @@ static void Radeon_SetTransform( accelerator_info *ai,
// convert Be colour key to rgb value
static uint32 colourKey2RGB32( uint32 space, uint8 red, uint8 green, uint8 blue )
static uint32 colourKey2RGB32(
uint32 space, uint8 red, uint8 green, uint8 blue )
{
uint32 res;
@@ -300,7 +303,8 @@ static uint32 colourKey2RGB32( uint32 space, uint8 red, uint8 green, uint8 blue
// set colour key of overlay
static void Radeon_SetColourKey( accelerator_info *ai, const overlay_window *ow )
static void Radeon_SetColourKey(
accelerator_info *ai, const overlay_window *ow )
{
virtual_card *vc = ai->vc;
vuint8 *regs = ai->regs;
@@ -437,7 +441,8 @@ static space_params space_params_table[16] = {
};
// get appropriate scaling/filter parameters
static hscale_factor *getHScaleFactor( space_params *params,
static hscale_factor *getHScaleFactor(
space_params *params,
uint32 src_left, uint32 src_right, uint32 *h_inc )
{
uint words_per_p1_line, words_per_p23_line, max_words_per_line;
@@ -511,14 +516,15 @@ static hscale_factor *getHScaleFactor( space_params *params,
// show overlay on screen
static status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_head *virtual_head )
static status_t Radeon_ShowOverlay(
accelerator_info *ai, int crtc_idx )
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
vuint8 *regs = ai->regs;
overlay_info *overlay = &si->pending_overlay;
overlay_buffer_node *node = overlay->on;
physical_head *head = &si->heads[virtual_head->physical_head];
crtc_info *crtc = &si->crtc[crtc_idx];
uint32 ecp_div;
uint32 v_inc, h_inc;
@@ -547,7 +553,7 @@ static status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_head *virtual_
// only every second pixel is handled
// (this devider is gets written into PLL by InitOverlay,
// so we don't need to do it ourself)
if( head->mode.timing.pixel_clock < 175000 )
if( crtc->mode.timing.pixel_clock < 175000 )
ecp_div = 0;
else
ecp_div = 1;
@@ -595,10 +601,10 @@ static status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_head *virtual_
// apply virtual screen
dest_left -= vc->mode.h_display_start + virtual_head->rel_x;
dest_top -= vc->mode.v_display_start + virtual_head->rel_y;
dest_right -= vc->mode.h_display_start + virtual_head->rel_x;
dest_bottom -= vc->mode.v_display_start + virtual_head->rel_y;
dest_left -= vc->mode.h_display_start + crtc->rel_x;
dest_top -= vc->mode.v_display_start + crtc->rel_y;
dest_right -= vc->mode.h_display_start + crtc->rel_x;
dest_bottom -= vc->mode.v_display_start + crtc->rel_y;
// clip to visible area
@@ -612,12 +618,12 @@ static status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_head *virtual_
}
SHOW_FLOW( 3, "mode: w=%d, h=%d",
head->mode.timing.h_display, head->mode.timing.v_display );
crtc->mode.timing.h_display, crtc->mode.timing.v_display );
if( dest_right > head->mode.timing.h_display )
dest_right = head->mode.timing.h_display;
if( dest_bottom > head->mode.timing.v_display )
dest_bottom = head->mode.timing.v_display;
if( dest_right > crtc->mode.timing.h_display )
dest_right = crtc->mode.timing.h_display;
if( dest_bottom > crtc->mode.timing.v_display )
dest_bottom = crtc->mode.timing.v_display;
SHOW_FLOW( 3, "src=(%d, %d, %d, %d)",
src_left, src_top, src_right, src_bottom );
@@ -718,16 +724,13 @@ static status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_head *virtual_
// TBD: there is no description at all concerning this, so v_accum_init may
// need to be initialized based on original value
{
display_device_e disp_devices;
disp_devices = head->active_displays;
if( (disp_devices & (dd_lvds | dd_dvi)) != 0 ) {
if( (crtc->active_displays & (dd_lvds | dd_dvi)) != 0 ) {
uint64 v_ratio;
// convert 32.32 format to 16.16 format; else we
// cannot multiply two fixed point values without
// overflow
v_ratio = si->flatpanels[head->flatpanel_port].v_ratio >> (FIX_SHIFT - 16);
v_ratio = si->flatpanels[crtc->flatpanel_port].v_ratio >> (FIX_SHIFT - 16);
v_inc = (v_inc * v_ratio) >> 16;
}
@@ -846,10 +849,10 @@ static status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_head *virtual_
OUTREG( regs, RADEON_OV0_V_INC, v_inc );
OUTREG( regs,
head->is_crtc2 ? RADEON_OV1_Y_X_START : RADEON_OV0_Y_X_START,
crtc->crtc_idx == 0 ? RADEON_OV0_Y_X_START : RADEON_OV1_Y_X_START,
(dest_left) | (dest_top << 16) );
OUTREG( regs,
head->is_crtc2 ? RADEON_OV1_Y_X_END : RADEON_OV0_Y_X_END,
crtc->crtc_idx == 0 ? RADEON_OV0_Y_X_END : RADEON_OV1_Y_X_END,
(dest_right - 1) | ((dest_bottom - 1) << 16) );
OUTREG( regs, RADEON_OV0_P1_BLANK_LINES_AT_TOP,
@@ -873,7 +876,7 @@ static status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_head *virtual_
RADEON_SCALER_DOUBLE_BUFFER |
(node->ati_space << 8) |
/*RADEON_SCALER_ADAPTIVE_DEINT |*/
(head->is_crtc2 ? RADEON_SCALER_CRTC_SEL : 0 ));
(crtc->crtc_idx == 0 ? 0 : RADEON_SCALER_CRTC_SEL ));
si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE;
@@ -895,7 +898,8 @@ done:
// hide overlay, but not permanently
void Radeon_TempHideOverlay( accelerator_info *ai )
void Radeon_TempHideOverlay(
accelerator_info *ai )
{
SHOW_FLOW0( 3, "" );
@@ -904,7 +908,8 @@ void Radeon_TempHideOverlay( accelerator_info *ai )
// hide overlay (can be called even if there is none visible)
void Radeon_HideOverlay( accelerator_info *ai )
void Radeon_HideOverlay(
accelerator_info *ai )
{
shared_info *si = ai->si;
@@ -917,12 +922,13 @@ void Radeon_HideOverlay( accelerator_info *ai )
// invalidate active head so it will be setup again once
// a new overlay is shown
si->active_overlay.head = -1;
si->active_overlay.crtc_idx = -1;
}
// show new overlay buffer with same parameters as last one
static void Radeon_ReplaceOverlayBuffer( accelerator_info *ai )
static void Radeon_ReplaceOverlayBuffer(
accelerator_info *ai )
{
#if 0
shared_info *si = ai->si;
@@ -984,14 +990,14 @@ static void Radeon_ReplaceOverlayBuffer( accelerator_info *ai )
// get number of pixels of overlay shown on virtual port
static int getIntersectArea( accelerator_info *ai, overlay_window *ow, virtual_head *virtual_head )
static int getIntersectArea(
accelerator_info *ai, overlay_window *ow, crtc_info *crtc )
{
virtual_card *vc = ai->vc;
physical_head *head = &ai->si->heads[virtual_head->physical_head];
int left, top, right, bottom;
left = ow->h_start - (vc->mode.h_display_start + virtual_head->rel_x);
top = ow->v_start - (vc->mode.v_display_start + virtual_head->rel_y);
left = ow->h_start - (vc->mode.h_display_start + crtc->rel_x);
top = ow->v_start - (vc->mode.v_display_start + crtc->rel_y);
right = left + ow->width;
bottom = top + ow->height;
@@ -999,10 +1005,10 @@ static int getIntersectArea( accelerator_info *ai, overlay_window *ow, virtual_h
left = 0;
if( top < 0 )
top = 0;
if( right > head->mode.timing.h_display )
right = head->mode.timing.h_display;
if( bottom > head->mode.timing.v_display )
bottom = head->mode.timing.v_display;
if( right > crtc->mode.timing.h_display )
right = crtc->mode.timing.h_display;
if( bottom > crtc->mode.timing.v_display )
bottom = crtc->mode.timing.v_display;
if( right < left || bottom < top )
return 0;
@@ -1013,12 +1019,12 @@ static int getIntersectArea( accelerator_info *ai, overlay_window *ow, virtual_h
// update overlay, to be called whenever something in terms of
// overlay have or can have been changed
status_t Radeon_UpdateOverlay( accelerator_info *ai )
status_t Radeon_UpdateOverlay(
accelerator_info *ai )
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
virtual_head *virtual_head;
physical_head *physical_head;
int crtc_idx;
float brightness = 0.0f;
float contrast = 1.0f;
@@ -1040,38 +1046,40 @@ status_t Radeon_UpdateOverlay( accelerator_info *ai )
if( (uint32)si->pending_overlay.ot != si->overlay_mgr.token )
return B_BAD_VALUE;
/* SHOW_FLOW( 3, "num_ports=%d, whished_overlay_port=%d",
vc->num_ports, vc->whished_overlay_port );*/
if( vc->different_heads > 1 ) {
int area0, area1;
// determine on which port most of the overlay is shown
area0 = getIntersectArea( ai, &si->pending_overlay.ow, &vc->heads[0] );
area1 = getIntersectArea( ai, &si->pending_overlay.ow, &vc->heads[1] );
area0 = getIntersectArea( ai, &si->pending_overlay.ow, &si->crtc[0] );
area1 = getIntersectArea( ai, &si->pending_overlay.ow, &si->crtc[0] );
SHOW_FLOW( 3, "area0=%d, area1=%d", area0, area1 );
if( area0 >= area1 )
virtual_head = &vc->heads[0];
crtc_idx = 0;
else
virtual_head = &vc->heads[1];
} else {
crtc_idx = 1;
} else if( vc->independant_heads > 1 ) {
// both ports show the same, use "swap displays" to decide
// where to show the overlay (to be improved as this flag isn't
// really designed for that)
if( vc->independant_heads > 1 && vc->swap_displays )
virtual_head = &vc->heads[1];
if( vc->swap_displays )
crtc_idx = 1;
else
virtual_head = &vc->heads[0];
crtc_idx = 0;
} else {
// one crtc used only - pick the one that we use
crtc_idx = vc->used_crtc[0] ? 0 : 1;
}
si->pending_overlay.head = virtual_head->physical_head;
physical_head = &si->heads[virtual_head->physical_head];
si->pending_overlay.crtc_idx = crtc_idx;
// only update registers that have been changed to minimize work
if( si->active_overlay.head != si->pending_overlay.head ) {
Radeon_InitOverlay( ai, physical_head );
if( si->active_overlay.crtc_idx != si->pending_overlay.crtc_idx ) {
Radeon_InitOverlay( ai, crtc_idx );
}
if( si->active_overlay.ob.space != si->pending_overlay.ob.space ) {
@@ -1085,7 +1093,7 @@ status_t Radeon_UpdateOverlay( accelerator_info *ai )
si->active_overlay.ob.width != si->pending_overlay.ob.width ||
si->active_overlay.ob.height != si->pending_overlay.ob.height ||
si->active_overlay.ob.bytes_per_row != si->pending_overlay.ob.bytes_per_row )
Radeon_ShowOverlay( ai, virtual_head );
Radeon_ShowOverlay( ai, crtc_idx );
else if( si->active_overlay.on != si->pending_overlay.on )
Radeon_ReplaceOverlayBuffer( ai );
+18 -15
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
@@ -18,20 +18,21 @@
// Radeon's DACs share same public registers, this function
// selects the DAC you'll talk to
#define selectPalette( head ) \
#define selectPalette( crtc_idx ) \
WRITE_IB_REG( RADEON_DAC_CNTL2, \
((head)->is_crtc2 ? RADEON_DAC2_PALETTE_ACC_CTL : 0) | \
(crtc_idx == 0 ? 0 : RADEON_DAC2_PALETTE_ACC_CTL) | \
(ai->si->dac_cntl2 & ~RADEON_DAC2_PALETTE_ACC_CTL) );
// set standard colour palette (needed for non-palette modes)
void Radeon_InitPalette( accelerator_info *ai, physical_head *head )
void Radeon_InitPalette(
accelerator_info *ai, int crtc_idx )
{
int i;
START_IB();
selectPalette( head );
selectPalette( crtc_idx );
WRITE_IB_REG( RADEON_PALETTE_INDEX, 0 );
@@ -41,14 +42,15 @@ void Radeon_InitPalette( accelerator_info *ai, physical_head *head )
SUBMIT_IB();
}
static void setPalette( accelerator_info *ai, physical_head *head,
static void setPalette(
accelerator_info *ai, int crtc_idx,
uint count, uint8 first, uint8 *color_data );
// public function: set colour palette
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags)
void SET_INDEXED_COLORS(
uint count, uint8 first, uint8 *color_data, uint32 flags )
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
(void)flags;
@@ -58,23 +60,24 @@ void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags
SHOW_ERROR0( 2, "Tried to set palette in non-palette mode" );
return;
}
setPalette( ai, &si->heads[vc->heads[0].physical_head], count, first, color_data );
if( vc->independant_heads > 1 )
setPalette( ai, &si->heads[vc->heads[1].physical_head], count, first, color_data );
if( vc->used_crtc[0] )
setPalette( ai, 0, count, first, color_data );
if( vc->used_crtc[1] )
setPalette( ai, 1, count, first, color_data );
}
// set palette of one DAC
static void setPalette( accelerator_info *ai, physical_head *head,
static void setPalette(
accelerator_info *ai, int crtc_idx,
uint count, uint8 first, uint8 *color_data )
{
uint i;
START_IB();
selectPalette( head );
selectPalette( crtc_idx );
WRITE_IB_REG( RADEON_PALETTE_INDEX, first );
+78 -67
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
@@ -14,9 +14,11 @@
#include "pll_access.h"
#include "utils.h"
#include <stdlib.h>
#include "set_mode.h"
static void Radeon_PLLWaitForReadUpdateComplete( accelerator_info *ai, physical_head *head )
static void Radeon_PLLWaitForReadUpdateComplete(
accelerator_info *ai, int crtc_idx )
{
int i;
@@ -24,18 +26,19 @@ static void Radeon_PLLWaitForReadUpdateComplete( accelerator_info *ai, physical_
// 1. this is unsafe
// 2. some r300 loop forever (reported by XFree86)
for( i = 0; i < 10000; ++i ) {
if( (Radeon_INPLL( ai->regs, ai->si->asic, head->is_crtc2 ? RADEON_P2PLL_REF_DIV : RADEON_PPLL_REF_DIV )
if( (Radeon_INPLL( ai->regs, ai->si->asic, crtc_idx == 0 ? RADEON_PPLL_REF_DIV : RADEON_P2PLL_REF_DIV )
& RADEON_PPLL_ATOMIC_UPDATE_R) == 0 )
return;
}
}
static void Radeon_PLLWriteUpdate( accelerator_info *ai, physical_head *head )
static void Radeon_PLLWriteUpdate(
accelerator_info *ai, int crtc_idx )
{
Radeon_PLLWaitForReadUpdateComplete( ai, head );
Radeon_PLLWaitForReadUpdateComplete( ai, crtc_idx );
Radeon_OUTPLLP( ai->regs, ai->si->asic,
head->is_crtc2 ? RADEON_P2PLL_REF_DIV : RADEON_PPLL_REF_DIV,
crtc_idx == 0 ? RADEON_PPLL_REF_DIV : RADEON_P2PLL_REF_DIV,
RADEON_PPLL_ATOMIC_UPDATE_W,
~RADEON_PPLL_ATOMIC_UPDATE_W );
}
@@ -45,7 +48,8 @@ static void Radeon_PLLWriteUpdate( accelerator_info *ai, physical_head *head )
// freq - whished frequency in Hz
// fixed_post_div - if != 0, fixed divider to be used
// dividers - filled with proper dividers
void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_div, pll_dividers *dividers )
void Radeon_CalcPLLDividers(
const pll_info *pll, uint32 freq, uint fixed_post_div, pll_dividers *dividers )
{
// the PLL gets the reference
// pll_in = ref_freq / ref_div
@@ -71,8 +75,9 @@ void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_d
best_post_div_idx, best_extra_post_div_idx;
uint32
best_ref_div, best_feedback_div,
best_freq, best_error, best_vco_dev;
best_ref_div, best_feedback_div, best_freq;
int32
best_error, best_vco_dev;
best_error = 999999999;
@@ -127,7 +132,8 @@ void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_d
// we can either iterate through feedback or reference dividers;
// usually, there are fewer possible reference dividers, so I picked them
for( ref_div = pll->min_ref_div; ref_div <= pll->max_ref_div; ++ref_div ) {
uint32 feedback_div, cur_freq, error, vco_dev;
uint32 feedback_div, cur_freq;
int32 error, vco_dev;
// this implies the frequency of the lock unit
uint32 pll_in = pll->ref_freq / ref_div;
@@ -144,17 +150,17 @@ void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_d
if( feedback_div < pll->min_feedback_div ||
feedback_div > pll->max_feedback_div )
continue;
// let's see what we've got
cur_freq = RoundDiv64(
(int64)pll->ref_freq * 10000 * feedback_div * pll->extra_feedback_div,
ref_div * post_div );
// absolute error in terms of output clock
error = abs( cur_freq - freq );
// deviation from perfect VCO clock
vco_dev = abs( vco - pll->best_vco );
// if there is no optimal VCO frequency, choose setting with less error;
// if there is an optimal VCO frequency, choose new settings if
// - error is reduced significantly (100 Hz or more), or
@@ -165,6 +171,7 @@ void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_d
(error < best_error - 100 ||
(abs( error - best_error ) < 100 && vco_dev < best_vco_dev ))))
{
//SHOW_FLOW( 2, "got freq=%d, best_freq=%d", freq, cur_freq );
best_post_div_idx = post_div_idx;
best_extra_post_div_idx = extra_post_div_idx;
best_ref_div = ref_div;
@@ -184,6 +191,10 @@ void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_d
dividers->ref = best_ref_div;
dividers->feedback = best_feedback_div;
dividers->freq = best_freq;
/*SHOW_FLOW( 2, "post_code=%d, post=%d, extra_post_code=%d, extra_post=%d, ref=%d, feedback=%d, freq=%d",
dividers->post_code, dividers->post, dividers->extra_post_code,
dividers->extra_post, dividers->ref, dividers->feedback, dividers->freq );*/
}
@@ -193,7 +204,7 @@ void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_d
// with precisely the same frame rate; the solution is to tweak the CRT
// image a bit by making it wider/taller/smaller until the frame rate
// drift is under a given threshold;
// we follows two aims:
// we follow two aims:
// - primary, keep frame rate in sync
// - secondary, only tweak as much as unavoidable
void Radeon_MatchCRTPLL(
@@ -267,7 +278,7 @@ void Radeon_MatchCRTPLL(
// if drift is within threshold, we take this setting and stop
// searching (later iteration will increasingly tweak screen size,
// and we don't really want that)
if( frame_rate_drift < max_frame_rate_drift ) {
if( frame_rate_drift <= max_frame_rate_drift ) {
SHOW_INFO( 2, "frame_rate_drift=%d, crt_freq=%d, v_total=%d, h_total=%d",
frame_rate_drift, crt_freq, v_total, h_total );
@@ -348,7 +359,7 @@ void Radeon_GetTVPLLConfiguration( const general_pll_info *general_pll, pll_info
// in the original code, they set it to 330kHz if PAL is requested and
// quartz is 27 MHz, but I don't see how these circumstances can effect the
// mimimal PLL input frequency
pll->pll_in_min = 40;
pll->pll_in_min = 20;//40;
// in the original code, they don't define an upper limit
pll->pll_in_max = 100;
pll->extra_feedback_div = 1;
@@ -391,47 +402,46 @@ void Radeon_GetTVCRTPLLConfiguration( const general_pll_info *general_pll, pll_i
}
// calc PLL dividers for CRT
// mode->timing.pixel_clock must be in Hz because required accuracy in TV-Out mode
void Radeon_CalcCRTPLLDividers(
const general_pll_info *general_pll, const display_mode *mode, pll_dividers *dividers )
{
pll_info pll;
pll.post_divs = post_divs;
pll.extra_post_divs = extra_post_divs;
pll.ref_freq = general_pll->ref_freq;
pll.vco_min = general_pll->min_pll_freq;
pll.vco_max = general_pll->max_pll_freq;
pll.min_ref_div = 2;
pll.max_ref_div = 0x3ff;
pll.pll_in_min = 40;
pll.pll_in_max = 100;
pll.extra_feedback_div = 1;
pll.min_feedback_div = 4;
pll.max_feedback_div = 0x7ff;
pll.best_vco = 0;
SHOW_FLOW( 2, "freq=%ld", mode->timing.pixel_clock );
Radeon_CalcPLLDividers( &pll, mode->timing.pixel_clock, 0, dividers );
}
// calculate PLL registers
// mode->timing.pixel_clock must be in Hz because required accuracy in TV-Out mode
// (old: freq is in 10kHz)
// fixed_dividers - if non-NULL, you can force a pre-calculated divider (used for TV-Out)
void Radeon_CalcPLLRegisters( general_pll_info *general_pll,
const display_mode *mode, pll_dividers *fixed_dividers, port_regs *values )
void Radeon_CalcPLLRegisters(
const display_mode *mode, const pll_dividers *dividers, pll_regs *values )
{
pll_dividers dividers;
values->dot_clock_freq = dividers->freq;
values->feedback_div = dividers->feedback;
values->post_div = dividers->post;
values->pll_output_freq = dividers->freq * dividers->post;
if( fixed_dividers == NULL ) {
pll_info pll;
pll.post_divs = post_divs;
pll.extra_post_divs = extra_post_divs;
pll.ref_freq = general_pll->ref_freq;
pll.vco_min = general_pll->min_pll_freq;
pll.vco_max = general_pll->max_pll_freq;
pll.min_ref_div = 2;
pll.max_ref_div = 0x3ff;
pll.pll_in_min = 40;
pll.pll_in_max = 100;
pll.extra_feedback_div = 1;
pll.min_feedback_div = 4;
pll.max_feedback_div = 0x7ff;
pll.best_vco = 0;
SHOW_FLOW( 2, "freq=%ld", mode->timing.pixel_clock/*freq * 10000*/ );
Radeon_CalcPLLDividers( &pll, mode->timing.pixel_clock /*freq * 10000*/, 0, &dividers );
} else {
// dividers are precalculated, so use them
dividers = *fixed_dividers;
}
values->dot_clock_freq = dividers.freq;
values->feedback_div = dividers.feedback;
values->post_div = dividers.post;
values->pll_output_freq = dividers.freq * dividers.post;
values->ppll_ref_div = dividers.ref;
values->ppll_div_3 = (dividers.feedback | (dividers.post_code << 16));
values->ppll_ref_div = dividers->ref;
values->ppll_div_3 = (dividers->feedback | (dividers->post_code << 16));
// this is mad: the PLL controls the horizontal length in sub-byte precision!
values->htotal_cntl = mode->timing.h_total & 7;
@@ -441,7 +451,8 @@ void Radeon_CalcPLLRegisters( general_pll_info *general_pll,
}
// write values into PLL registers
void Radeon_ProgramPLL( accelerator_info *ai, physical_head *head, port_regs *values )
void Radeon_ProgramPLL(
accelerator_info *ai, int crtc_idx, pll_regs *values )
{
vuint8 *regs = ai->regs;
radeon_type asic = ai->si->asic;
@@ -450,11 +461,11 @@ void Radeon_ProgramPLL( accelerator_info *ai, physical_head *head, port_regs *va
// use some other PLL for pixel clock source to not fiddling with PLL
// while somebody is using it
Radeon_OUTPLLP( regs, asic, head->is_crtc2 ? RADEON_PIXCLKS_CNTL : RADEON_VCLK_ECP_CNTL,
Radeon_OUTPLLP( regs, asic, crtc_idx == 0 ? RADEON_VCLK_ECP_CNTL : RADEON_PIXCLKS_CNTL,
RADEON_VCLK_SRC_CPU_CLK, ~RADEON_VCLK_SRC_SEL_MASK );
Radeon_OUTPLLP( regs, asic,
head->is_crtc2 ? RADEON_P2PLL_CNTL : RADEON_PPLL_CNTL,
crtc_idx == 0 ? RADEON_PPLL_CNTL : RADEON_P2PLL_CNTL,
RADEON_PPLL_RESET
| RADEON_PPLL_ATOMIC_UPDATE_EN
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN,
@@ -467,40 +478,40 @@ void Radeon_ProgramPLL( accelerator_info *ai, physical_head *head, port_regs *va
RADEON_PLL_DIV_SEL_DIV3,
~RADEON_PLL_DIV_SEL_MASK );
if( ai->si->asic >= rt_r300 && !head->is_crtc2 ) {
// with r300, the reference divider of the first PLL was moved
// to another bit position; at the old location, you only find
// the "BIOS suggested divider"; no clue why they did that
if( ai->si->new_pll && crtc_idx == 0 ) {
// starting with r300, the reference divider of the first PLL was
// moved to another bit position; at the old location, you only
// find the "BIOS suggested divider"; no clue why they did that
Radeon_OUTPLLP( regs, asic,
RADEON_PPLL_REF_DIV,
values->ppll_ref_div << RADEON_PPLL_REF_DIV_ACC_SHIFT,
~RADEON_PPLL_REF_DIV_ACC_MASK );
} else {
Radeon_OUTPLLP( regs, asic,
head->is_crtc2 ? RADEON_P2PLL_REF_DIV : RADEON_PPLL_REF_DIV,
crtc_idx == 0 ? RADEON_PPLL_REF_DIV : RADEON_P2PLL_REF_DIV,
values->ppll_ref_div,
~RADEON_PPLL_REF_DIV_MASK );
}
Radeon_OUTPLLP( regs, asic,
head->is_crtc2 ? RADEON_P2PLL_DIV_0 : RADEON_PPLL_DIV_3,
crtc_idx == 0 ? RADEON_PPLL_DIV_3 : RADEON_P2PLL_DIV_0,
values->ppll_div_3,
~RADEON_PPLL_FB3_DIV_MASK );
Radeon_OUTPLLP( regs, asic,
head->is_crtc2 ? RADEON_P2PLL_DIV_0 : RADEON_PPLL_DIV_3,
crtc_idx == 0 ? RADEON_PPLL_DIV_3 : RADEON_P2PLL_DIV_0,
values->ppll_div_3,
~RADEON_PPLL_POST3_DIV_MASK );
Radeon_PLLWriteUpdate( ai, head );
Radeon_PLLWaitForReadUpdateComplete( ai, head );
Radeon_PLLWriteUpdate( ai, crtc_idx );
Radeon_PLLWaitForReadUpdateComplete( ai, crtc_idx );
Radeon_OUTPLL( regs, asic,
head->is_crtc2 ? RADEON_HTOTAL2_CNTL : RADEON_HTOTAL_CNTL,
crtc_idx == 0 ? RADEON_HTOTAL_CNTL : RADEON_HTOTAL2_CNTL,
values->htotal_cntl );
Radeon_OUTPLLP( regs, asic,
head->is_crtc2 ? RADEON_P2PLL_CNTL : RADEON_PPLL_CNTL, 0,
crtc_idx == 0 ? RADEON_PPLL_CNTL : RADEON_P2PLL_CNTL, 0,
~(RADEON_PPLL_RESET
| RADEON_PPLL_SLEEP
| RADEON_PPLL_ATOMIC_UPDATE_EN
@@ -511,6 +522,6 @@ void Radeon_ProgramPLL( accelerator_info *ai, physical_head *head, port_regs *va
// use PLL for pixel clock again
Radeon_OUTPLLP( regs, asic,
head->is_crtc2 ? RADEON_PIXCLKS_CNTL : RADEON_VCLK_ECP_CNTL,
crtc_idx == 0 ? RADEON_VCLK_ECP_CNTL : RADEON_PIXCLKS_CNTL,
RADEON_VCLK_SRC_PPLL_CLK, ~RADEON_VCLK_SRC_SEL_MASK );
}
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Copyright (c) 2002-2005, Thomas Kurschel
Part of Radeon accelerant
@@ -18,12 +18,10 @@
extern "C" {
#endif
#ifndef __HAIKU__
void _kdprintf_(const char *format, ...);
#define dprintf _kdprintf_
#else
#define dprintf _sPrintf
#endif
void _sPrintf(const char *format, ...);
//bool set_dprintf_enabled(bool); /* returns old enable flag */
#define dprintf _sPrintf
extern int debug_level_flow;
extern int debug_level_info;
@@ -32,7 +30,7 @@ extern int debug_level_error;
/*#define DEBUG_WAIT_ON_MSG 1000000
#define DEBUG_WAIT_ON_ERROR 1000000*/
#define DEBUG_MSG_PREFIX "Radeon Acc - "
#define DEBUG_MSG_PREFIX "Radeon - "
#define DEBUG_MAX_LEVEL_FLOW 2
@@ -41,9 +39,11 @@ extern int debug_level_error;
// info about this accelerant
typedef struct accelerator_info {
shared_info *si; // info shared between accelerants
virtual_card *vc; // associated virtual card
vuint8 *regs; // pointer to mapped registers
// !! dont't make it vuint32, access macros rely on 8 bits !!
area_id shared_info_area; // info shared between accelerants
area_id regs_area; // MM I/O registers
area_id virtual_card_area; // info about virtual card
@@ -64,30 +64,27 @@ typedef struct accelerator_info {
area_id mode_list_area; // cloned list of standard display modes
display_mode *mode_list; // list of standard display modes
shared_info *si; // info shared between accelerants
} accelerator_info;
#define IS_INTERNAL_TV_OUT( tv_chip ) \
( (tv_chip) == tc_internal_rt1 || (tv_chip) == tc_internal_rt2 )
// vesa_modes.c
extern const display_timing vesa_mode_list[];
extern const size_t vesa_mode_list_count;
// SetDisplayMode.c
uint32 Radeon_RoundVWidth( int virtual_width, int bpp );
status_t Radeon_MoveDisplay( accelerator_info *ai, uint16 h_display_start, uint16 v_display_start );
// crtc.c
void Radeon_ReadCRTCRegisters( accelerator_info *ai, physical_head *head,
port_regs *values );
uint16 Radeon_GetHSyncFudge( physical_head *head, int datatype );
void Radeon_CalcCRTCRegisters( accelerator_info *ai, physical_head *head,
display_mode *mode, port_regs *values );
void Radeon_ProgramCRTCRegisters( accelerator_info *ai, physical_head *head,
port_regs *values );
// multimon.c
void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode );
void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode );
void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mode );
void Radeon_InitMultiModeVars( virtual_card *vc, display_mode *mode );
void Radeon_InitMultiModeVars( accelerator_info *ai, display_mode *mode );
status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
const display_mode *low, const display_mode *high, bool *isTunnel );
bool Radeon_NeedsSecondPort( display_mode *mode );
@@ -99,42 +96,14 @@ bool Radeon_GetFormat( int space, int *format, int *bpp );
status_t Radeon_CreateModeList( shared_info *si );
// pll.c
void Radeon_CalcPLLRegisters( general_pll_info *pll, const display_mode *mode, pll_dividers *fixed_dividers, port_regs *values );
void Radeon_ProgramPLL( accelerator_info *ai, physical_head *head, port_regs *values );
void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_div, pll_dividers *dividers );
void Radeon_MatchCRTPLL(
const pll_info *pll,
uint32 tv_v_total, uint32 tv_h_total, uint32 tv_frame_size_adjust, uint32 freq,
const display_mode *mode, uint32 max_v_tweak, uint32 max_h_tweak,
uint32 max_frame_rate_drift, uint32 fixed_post_div,
pll_dividers *dividers,
display_mode *tweaked_mode );
void Radeon_GetTVPLLConfiguration( const general_pll_info *general_pll, pll_info *pll,
bool internal_encoder );
void Radeon_GetTVCRTPLLConfiguration( const general_pll_info *general_pll, pll_info *pll,
bool internal_tv_encoder );
// flat_panel.c
void Radeon_ReadRMXRegisters( accelerator_info *ai, port_regs *values );
void Radeon_CalcRMXRegisters( fp_info *flatpanel, display_mode *mode, bool use_rmx, port_regs *values );
void Radeon_ProgramRMXRegisters( accelerator_info *ai, port_regs *values );
void Radeon_ReadFPRegisters( accelerator_info *ai, port_regs *values );
void Radeon_CalcFPRegisters( accelerator_info *ai, physical_head *head,
fp_info *fp_port, port_regs *values );
void Radeon_ProgramFPRegisters( accelerator_info *ai, physical_head *head,
fp_info *fp_port, port_regs *values );
// dpms.c
status_t Radeon_SetDPMS( accelerator_info *ai, physical_head *head, int mode );
uint32 Radeon_GetDPMS( accelerator_info *ai, physical_head *head );
status_t Radeon_SetDPMS( accelerator_info *ai, int crtc_idx, int mode );
uint32 Radeon_GetDPMS( accelerator_info *ai, int crtc_idx );
// Cursor.c
void Radeon_SetCursorColors( accelerator_info *ai, physical_head *head );
void Radeon_SetCursorColors( accelerator_info *ai, int crtc_idx );
void Radeon_ShowCursor( accelerator_info *ai, int crtc_idx );
// Acceleration.c
@@ -171,32 +140,13 @@ void Radeon_Spin( uint32 delay );
void Radeon_DetectDisplays( accelerator_info *ai );
// tv_out.c
void Radeon_DetectTVOut( accelerator_info *ai );
void Radeon_CalcTVParams( const general_pll_info *general_pll, tv_params *params,
const tv_timing *tv_timing, bool internal_encoder,
const display_mode *mode, display_mode *tweaked_mode );
void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing *timing,
tv_params *params, port_regs *values, physical_head *head,
bool internal_encoder, tv_standard tv_format );
void Radeon_ProgramTVRegisters( accelerator_info *ai, port_regs *values, bool internal_encoder );
void Radeon_ReadTVRegisters( accelerator_info *ai, port_regs *values, bool internal_encoder );
extern tv_timing Radeon_std_tv_timing[6];
// palette.c
void Radeon_InitPalette( accelerator_info *ai, physical_head *head );
void Radeon_InitPalette( accelerator_info *ai, int crtc_idx );
// monitor_routing.h
void Radeon_ReadMonitorRoutingRegs( accelerator_info *ai, physical_head *head,
port_regs *values );
void Radeon_CalcMonitorRouting( accelerator_info *ai, physical_head *head,
port_regs *values );
void Radeon_ProgramMonitorRouting( accelerator_info *ai, physical_head *head, port_regs *values );
void Radeon_SetupDefaultMonitorRouting( accelerator_info *ai, int whished_num_heads );
// theatre_out.c
void Radeon_DetectTVOut( accelerator_info *ai );
#ifdef __cplusplus
}
+280
View File
@@ -0,0 +1,280 @@
/*
Copyright (c) 2002-04, Thomas Kurschel
Part of Radeon accelerant
Header file explicitely for display mode changes
*/
#ifndef _SET_MODE_H
#define _SET_MODE_H
// PLL divider values
typedef struct {
uint32 post_code; // code for post divider
uint32 post; // value of post divider
uint32 extra_post_code; // code for extra post divider
uint32 extra_post; // value of extra post divider
uint32 ref; // reference divider
uint32 feedback; // feedback divider
uint32 freq; // resulting frequency
} pll_dividers;
// TV-timing
typedef struct {
uint32 freq; // TV sub carrier frequency x12
uint16 h_total;
uint16 h_sync_len;
uint16 h_genclk_delay;
uint16 h_setup_delay;
uint16 h_active_delay;
uint16 h_active_len;
uint16 v_total;
uint16 v_active_lines;
uint16 v_field_total;
uint16 v_fields;
uint16 f_total;
uint16 frame_size_adjust;
uint32 scale;
} tv_timing;
// TV-Out parameters
typedef struct {
uint16 y_accum_init;
uint16 uv_accum_init;
uint16 uv_inc;
uint16 h_inc;
uint32 tv_clocks_to_active;
uint16 f_restart;
uint16 v_restart;
uint16 h_restart;
bool mode888;
uint16 y_saw_tooth_slope;
uint16 y_saw_tooth_amp;
uint16 y_rise_accum_init;
uint16 y_fall_accum_init;
bool y_coeff_enable;
uint8 y_coeff_value;
pll_dividers tv_dividers;
pll_dividers crt_dividers;
tv_timing timing;
} impactv_params;
// CRTC register content (for mode change)
typedef struct {
uint32 crtc_h_total_disp;
uint32 crtc_h_sync_strt_wid;
uint32 crtc_v_total_disp;
uint32 crtc_v_sync_strt_wid;
uint32 crtc_pitch;
uint32 crtc_gen_cntl;
uint32 crtc_offset_cntl;
} crtc_regs;
// PLL register content (for mode change)
typedef struct {
uint32 ppll_div_3;
uint32 ppll_ref_div;
uint32 htotal_cntl;
// pure information
uint32 dot_clock_freq; // in 10 kHz
uint32 pll_output_freq;// in 10 kHz
int feedback_div;
int post_div;
} pll_regs;
// Flat Panel register content (for mode change)
typedef struct {
uint32 fp_gen_cntl;
uint32 fp_panel_cntl;
uint32 lvds_gen_cntl;
uint32 fp_h_sync_strt_wid;
uint32 fp_v_sync_strt_wid;
uint32 fp2_gen_cntl;
uint32 fp2_h_sync_strt_wid;
uint32 fp2_v_sync_strt_wid;
// RMX registers
uint32 fp_horz_stretch;
uint32 fp_vert_stretch;
} fp_regs;
#define RADEON_TV_TIMING_SIZE 32
#define RADEON_TV_UPSAMP_COEFF_NUM (5*3)
// ImpacTV-Out regs (for mode change)
typedef struct {
uint32 tv_ftotal;
uint32 tv_vscaler_cntl1;
uint32 tv_y_saw_tooth_cntl;
uint32 tv_y_fall_cntl;
uint32 tv_y_rise_cntl;
uint32 tv_vscaler_cntl2;
uint32 tv_hrestart;
uint32 tv_vrestart;
uint32 tv_frestart;
uint32 tv_tv_pll_cntl;
uint32 tv_crt_pll_cntl;
uint32 tv_clock_sel_cntl;
uint32 tv_clkout_cntl;
uint32 tv_htotal;
uint32 tv_hsize;
uint32 tv_hdisp;
uint32 tv_hstart;
uint32 tv_vtotal;
uint32 tv_vdisp;
uint32 tv_sync_size;
uint32 tv_timing_cntl;
uint32 tv_modulator_cntl1;
uint32 tv_modulator_cntl2;
uint32 tv_data_delay_a;
uint32 tv_data_delay_b;
uint32 tv_frame_lock_cntl;
uint32 tv_pll_cntl1;
uint32 tv_rgb_cntl;
uint32 tv_pre_dac_mux_cntl;
uint32 tv_master_cntl;
uint32 tv_dac_cntl;
uint32 tv_uv_adr;
uint32 tv_pll_fine_cntl;
uint32 tv_gain_limit_settings;
uint32 tv_linear_gain_settings;
uint32 tv_upsamp_and_gain_cntl;
uint32 tv_crc_cntl;
uint16 tv_hor_timing[RADEON_TV_TIMING_SIZE];
uint16 tv_vert_timing[RADEON_TV_TIMING_SIZE];
uint32 tv_upsample_filter_coeff[RADEON_TV_UPSAMP_COEFF_NUM];
} impactv_regs;
// Monitor Signal Routing regs (for mode change)
// (they collide with many other *_regs, so take
// care to set only the bits really used for routing)
typedef struct {
// DAC registers
uint32 dac_cntl2;
uint32 dac_cntl;
uint32 tv_master_cntl;
uint32 tv_dac_cntl;
bool skip_tv_dac; // if true, don't write tv_dac_cntl
// Display path registers
uint32 disp_hw_debug;
uint32 disp_output_cntl;
uint32 disp_tv_out_cntl;
// CRTC registers
uint32 crtc_ext_cntl;
uint32 crtc2_gen_cntl;
// PLL regs
uint32 vclk_ecp_cntl;
uint32 pixclks_cntl;
// GP IO-pad
uint32 gpiopad_a;
// flat panel registers
uint32 fp_gen_cntl;
uint32 fp2_gen_cntl;
} routing_regs;
// crtc.c
uint16 Radeon_GetHSyncFudge( crtc_info *crtc, int datatype );
void Radeon_CalcCRTCRegisters( accelerator_info *ai, crtc_info *crtc,
display_mode *mode, crtc_regs *values );
void Radeon_ProgramCRTCRegisters( accelerator_info *ai, int crtc_idx,
crtc_regs *values );
// pll.c
void Radeon_CalcCRTPLLDividers( const general_pll_info *general_pll, const display_mode *mode, pll_dividers *dividers );
void Radeon_CalcPLLRegisters( const display_mode *mode, const pll_dividers *dividers, pll_regs *values );
void Radeon_ProgramPLL( accelerator_info *ai, int crtc_idx, pll_regs *values );
void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_div, pll_dividers *dividers );
void Radeon_MatchCRTPLL(
const pll_info *pll,
uint32 tv_v_total, uint32 tv_h_total, uint32 tv_frame_size_adjust, uint32 freq,
const display_mode *mode, uint32 max_v_tweak, uint32 max_h_tweak,
uint32 max_frame_rate_drift, uint32 fixed_post_div,
pll_dividers *dividers,
display_mode *tweaked_mode );
void Radeon_GetTVPLLConfiguration( const general_pll_info *general_pll, pll_info *pll,
bool internal_encoder );
void Radeon_GetTVCRTPLLConfiguration( const general_pll_info *general_pll, pll_info *pll,
bool internal_tv_encoder );
// flat_panel.c
void Radeon_ReadRMXRegisters( accelerator_info *ai, fp_regs *values );
void Radeon_CalcRMXRegisters( fp_info *flatpanel, display_mode *mode, bool use_rmx, fp_regs *values );
void Radeon_ProgramRMXRegisters( accelerator_info *ai, fp_regs *values );
void Radeon_ReadFPRegisters( accelerator_info *ai, fp_regs *values );
void Radeon_CalcFPRegisters( accelerator_info *ai, crtc_info *crtc,
fp_info *fp_port, crtc_regs *crtc_values, fp_regs *values );
void Radeon_ProgramFPRegisters( accelerator_info *ai, crtc_info *crtc,
fp_info *fp_port, fp_regs *values );
// monitor_routing.h
void Radeon_ReadMonitorRoutingRegs(
accelerator_info *ai, routing_regs *values );
void Radeon_CalcMonitorRouting(
accelerator_info *ai, const impactv_params *tv_parameters, routing_regs *values );
void Radeon_ProgramMonitorRouting(
accelerator_info *ai, routing_regs *values );
void Radeon_SetupDefaultMonitorRouting(
accelerator_info *ai, int whished_num_heads, bool use_laptop_panel );
// impactv.c
typedef void (*impactv_write_FIFO) (
accelerator_info *ai, uint16 addr, uint32 value );
typedef uint32 (*impactv_read_FIFO) (
accelerator_info *ai, uint16 addr );
void Radeon_CalcImpacTVParams(
const general_pll_info *general_pll, impactv_params *params,
tv_standard_e tv_format, bool internal_encoder,
const display_mode *mode, display_mode *tweaked_mode );
void Radeon_CalcImpacTVRegisters(
accelerator_info *ai, display_mode *mode,
impactv_params *params, impactv_regs *values, int crtc_idx,
bool internal_encoder, tv_standard_e tv_format, display_device_e display_device );
void Radeon_ImpacTVwriteHorTimingTable(
accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values, bool internal_encoder );
void Radeon_ImpacTVwriteVertTimingTable(
accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values );
// theatre_out.c
void Radeon_TheatreProgramTVRegisters( accelerator_info *ai, impactv_regs *values );
void Radeon_TheatreReadTVRegisters( accelerator_info *ai, impactv_regs *values );
uint32 Radeon_TheatreReadFIFO( accelerator_info *ai, uint16 addr );
void Radeon_TheatreWriteFIFO( accelerator_info *ai, uint16 addr, uint32 value );
// internal_tv_out.c
void Radeon_InternalTVOutProgramRegisters( accelerator_info *ai, impactv_regs *values );
void Radeon_InternalTVOutReadRegisters( accelerator_info *ai, impactv_regs *values );
#endif
+10 -30
View File
@@ -30,13 +30,9 @@ void Radeon_ReadSettings( virtual_card *vc )
BPath path;
int32 tmp;
// per default we enable combine mode;
// if actual mode isn't combine mode, we fall back to clone mode
vc->wanted_multi_mode = mm_combine;
vc->swap_displays = false;
// per default, show overlay on first port
//vc->whished_overlay_port = 0;
vc->use_laptop_panel = false;
vc->tv_standard = ts_ntsc;
// this is problematic during boot: if there is multi-user support,
// you don't have a user when app_server gets launched;
@@ -56,27 +52,12 @@ void Radeon_ReadSettings( virtual_card *vc )
if( settings.Unflatten( &file ) != B_OK )
return;
if( settings.FindBool( "SwapDisplays", &vc->swap_displays ) != B_OK )
vc->swap_displays = false;
if( settings.FindInt32( "MultiMonitorMode", &tmp ) != B_OK )
tmp = mm_combine;
switch( tmp ) {
case mm_none:
case mm_mirror:
case mm_combine:
case mm_clone:
vc->wanted_multi_mode = (multi_mode_e) tmp;
break;
default:
vc->wanted_multi_mode = mm_combine;
}
settings.FindBool( "SwapDisplays", &vc->swap_displays );
settings.FindBool( "UseLaptopPanel", &vc->use_laptop_panel );
settings.FindInt32( "TVStandard", &tmp );
if( settings.FindInt32( "OverlayPort", &tmp ) != B_OK )
tmp = 0;
//vc->whished_overlay_port = tmp;
if( tmp >= 0 && tmp <= ts_max )
vc->tv_standard = (tv_standard_e)tmp;
}
void Radeon_WriteSettings( virtual_card *vc )
@@ -100,10 +81,9 @@ void Radeon_WriteSettings( virtual_card *vc )
BMessage settings;
settings.AddBool( "SwapDisplays", vc->swap_displays );
tmp = vc->wanted_multi_mode;
settings.AddInt32( "MultiMonitorMode", tmp );
/*tmp = vc->whished_overlay_port;
settings.AddInt32( "OverlayPort", tmp );*/
settings.AddBool( "UseLaptopPanel", vc->use_laptop_panel );
tmp = vc->tv_standard;
settings.AddInt32( "TVStandard", tmp );
settings.Flatten( &file );
}
@@ -0,0 +1,270 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Part of Radeon accelerant
Programming of TV-out via Rage Theatre
*/
#include "radeon_interface.h"
#include "radeon_accelerant.h"
#include "theatre_regs.h"
#include "tv_out_regs.h"
#include "set_mode.h"
#include <stdlib.h>
// mapping of offset in impactv_regs to register address
typedef struct register_mapping {
uint16 address; // register address
uint16 offset; // offset in impactv_regs
} register_mapping;
// Rage Theatre TV-Out:
// registers to write at first
static const register_mapping theatre_reg_mapping_start[] = {
{ THEATRE_VIP_MASTER_CNTL, offsetof( impactv_regs, tv_master_cntl ) },
{ THEATRE_VIP_TVO_DATA_DELAY_A, offsetof( impactv_regs, tv_data_delay_a ) },
{ THEATRE_VIP_TVO_DATA_DELAY_B, offsetof( impactv_regs, tv_data_delay_b ) },
{ THEATRE_VIP_CLKOUT_CNTL, offsetof( impactv_regs, tv_clkout_cntl ) },
{ THEATRE_VIP_PLL_CNTL0, offsetof( impactv_regs, tv_pll_cntl1 ) },
{ THEATRE_VIP_HRESTART, offsetof( impactv_regs, tv_hrestart ) },
{ THEATRE_VIP_VRESTART, offsetof( impactv_regs, tv_vrestart ) },
{ THEATRE_VIP_FRESTART, offsetof( impactv_regs, tv_frestart ) },
{ THEATRE_VIP_FTOTAL, offsetof( impactv_regs, tv_ftotal ) },
{ THEATRE_VIP_CLOCK_SEL_CNTL, offsetof( impactv_regs, tv_clock_sel_cntl ) },
{ THEATRE_VIP_TV_PLL_CNTL, offsetof( impactv_regs, tv_tv_pll_cntl ) },
{ THEATRE_VIP_CRT_PLL_CNTL, offsetof( impactv_regs, tv_crt_pll_cntl ) },
{ THEATRE_VIP_HTOTAL, offsetof( impactv_regs, tv_htotal ) },
{ THEATRE_VIP_HSIZE, offsetof( impactv_regs, tv_hsize ) },
{ THEATRE_VIP_HDISP, offsetof( impactv_regs, tv_hdisp ) },
{ THEATRE_VIP_HSTART, offsetof( impactv_regs, tv_hstart ) },
{ THEATRE_VIP_VTOTAL, offsetof( impactv_regs, tv_vtotal ) },
{ THEATRE_VIP_VDISP, offsetof( impactv_regs, tv_vdisp ) },
{ THEATRE_VIP_TIMING_CNTL, offsetof( impactv_regs, tv_timing_cntl ) },
{ THEATRE_VIP_VSCALER_CNTL, offsetof( impactv_regs, tv_vscaler_cntl1 ) },
{ THEATRE_VIP_VSCALER_CNTL2, offsetof( impactv_regs, tv_vscaler_cntl2 ) },
{ THEATRE_VIP_SYNC_SIZE, offsetof( impactv_regs, tv_sync_size ) },
{ THEATRE_VIP_Y_SAW_TOOTH_CNTL, offsetof( impactv_regs, tv_y_saw_tooth_cntl ) },
{ THEATRE_VIP_Y_RISE_CNTL, offsetof( impactv_regs, tv_y_rise_cntl ) },
{ THEATRE_VIP_Y_FALL_CNTL, offsetof( impactv_regs, tv_y_fall_cntl ) },
{ THEATRE_VIP_MODULATOR_CNTL1, offsetof( impactv_regs, tv_modulator_cntl1 ) },
{ THEATRE_VIP_MODULATOR_CNTL2, offsetof( impactv_regs, tv_modulator_cntl2 ) },
{ THEATRE_VIP_RGB_CNTL, offsetof( impactv_regs, tv_rgb_cntl ) },
{ THEATRE_VIP_UV_ADR, offsetof( impactv_regs, tv_uv_adr ) },
{ THEATRE_VIP_PRE_DAC_MUX_CNTL, offsetof( impactv_regs, tv_pre_dac_mux_cntl ) },
{ THEATRE_VIP_FRAME_LOCK_CNTL, offsetof( impactv_regs, tv_frame_lock_cntl ) },
{ THEATRE_VIP_CRC_CNTL, offsetof( impactv_regs, tv_crc_cntl ) },
{ 0, 0 }
};
// registers to write when things settled down
static const register_mapping theatre_reg_mapping_finish[] = {
{ THEATRE_VIP_UPSAMP_COEFF0_0, offsetof( impactv_regs, tv_upsample_filter_coeff[0*3+0] ) },
{ THEATRE_VIP_UPSAMP_COEFF0_1, offsetof( impactv_regs, tv_upsample_filter_coeff[0*3+1] ) },
{ THEATRE_VIP_UPSAMP_COEFF0_2, offsetof( impactv_regs, tv_upsample_filter_coeff[0*3+2] ) },
{ THEATRE_VIP_UPSAMP_COEFF1_0, offsetof( impactv_regs, tv_upsample_filter_coeff[1*3+0] ) },
{ THEATRE_VIP_UPSAMP_COEFF1_1, offsetof( impactv_regs, tv_upsample_filter_coeff[1*3+1] ) },
{ THEATRE_VIP_UPSAMP_COEFF1_2, offsetof( impactv_regs, tv_upsample_filter_coeff[1*3+2] ) },
{ THEATRE_VIP_UPSAMP_COEFF2_0, offsetof( impactv_regs, tv_upsample_filter_coeff[2*3+0] ) },
{ THEATRE_VIP_UPSAMP_COEFF2_1, offsetof( impactv_regs, tv_upsample_filter_coeff[2*3+1] ) },
{ THEATRE_VIP_UPSAMP_COEFF2_2, offsetof( impactv_regs, tv_upsample_filter_coeff[2*3+2] ) },
{ THEATRE_VIP_UPSAMP_COEFF3_0, offsetof( impactv_regs, tv_upsample_filter_coeff[3*3+0] ) },
{ THEATRE_VIP_UPSAMP_COEFF3_1, offsetof( impactv_regs, tv_upsample_filter_coeff[3*3+1] ) },
{ THEATRE_VIP_UPSAMP_COEFF3_2, offsetof( impactv_regs, tv_upsample_filter_coeff[3*3+2] ) },
{ THEATRE_VIP_UPSAMP_COEFF4_0, offsetof( impactv_regs, tv_upsample_filter_coeff[4*3+0] ) },
{ THEATRE_VIP_UPSAMP_COEFF4_1, offsetof( impactv_regs, tv_upsample_filter_coeff[4*3+1] ) },
{ THEATRE_VIP_UPSAMP_COEFF4_2, offsetof( impactv_regs, tv_upsample_filter_coeff[4*3+2] ) },
{ THEATRE_VIP_GAIN_LIMIT_SETTINGS, offsetof( impactv_regs, tv_gain_limit_settings ) },
{ THEATRE_VIP_LINEAR_GAIN_SETTINGS, offsetof( impactv_regs, tv_linear_gain_settings ) },
{ THEATRE_VIP_UPSAMP_AND_GAIN_CNTL, offsetof( impactv_regs, tv_upsamp_and_gain_cntl ) },
{ THEATRE_VIP_TV_DAC_CNTL, offsetof( impactv_regs, tv_dac_cntl ) },
{ THEATRE_VIP_MASTER_CNTL, offsetof( impactv_regs, tv_master_cntl ) },
{ 0, 0 }
};
// write list of Rage Theatre registers
static void writeTheatreRegList(
accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
{
for( ; mapping->address != 0 || mapping->offset != 0; ++mapping ) {
Radeon_VIPWrite( ai, ai->si->theatre_channel, mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );
/* SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );*/
}
}
// read timing FIFO
uint32 Radeon_TheatreReadFIFO(
accelerator_info *ai, uint16 addr )
{
bigtime_t start_time;
uint32 res = ~0;
//SHOW_FLOW( 2, "addr=%d", addr );
Radeon_VIPWrite( ai, ai->si->theatre_channel,
THEATRE_VIP_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_RD );
start_time = system_time();
do {
uint32 status;
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_RD_WT_CNTL, &status );
if( (status & RADEON_TV_HOST_RD_WT_CNTL_RD_ACK) != 0 )
break;
} while( system_time() - start_time < 2000000 );
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_RD_WT_CNTL, 0);
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_READ_DATA, &res );
return res;
}
// write to timing FIFO
void Radeon_TheatreWriteFIFO(
accelerator_info *ai, uint16 addr, uint32 value )
{
bigtime_t start_time;
//readFIFO( ai, addr, internal_encoder );
//SHOW_FLOW( 2, "addr=%d, value=%x %x", addr, value >> 14, value & 0x3fff );
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_WRITE_DATA, value);
Radeon_VIPWrite( ai, ai->si->theatre_channel,
THEATRE_VIP_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_WT);
start_time = system_time();
do {
uint32 status;
Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_RD_WT_CNTL, &status );
if( (status & RADEON_TV_HOST_RD_WT_CNTL_WT_ACK) != 0 )
break;
} while( system_time() - start_time < 2000000 );
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_RD_WT_CNTL, 0 );
}
// program TV-Out registers
void Radeon_TheatreProgramTVRegisters(
accelerator_info *ai, impactv_regs *values )
{
uint32 orig_tv_master_cntl = values->tv_master_cntl;
SHOW_FLOW0( 2, "" );
// disable TV-out when registers are setup
// it gets enabled again when things have settled down
values->tv_master_cntl |=
RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST |
RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST |
RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST |
RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST;
writeTheatreRegList( ai, values, theatre_reg_mapping_start );
// un-reset FIFO to access timing table
Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL,
orig_tv_master_cntl |
RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST |
RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST |
RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST );
Radeon_ImpacTVwriteHorTimingTable( ai, Radeon_TheatreWriteFIFO, values, false );
Radeon_ImpacTVwriteVertTimingTable( ai, Radeon_TheatreWriteFIFO, values );
snooze( 50000 );
values->tv_master_cntl = orig_tv_master_cntl;
writeTheatreRegList( ai, values, theatre_reg_mapping_finish );
}
// read list of Rage Theatre registers
static void readTheatreRegList(
accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
{
for( ; mapping->address != 0 || mapping->offset != 0; ++mapping ) {
Radeon_VIPRead( ai, ai->si->theatre_channel, mapping->address,
(uint32 *)((char *)(values) + mapping->offset) );
/*SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );*/
}
//snooze( 1000000 );
}
// read TV-Out registers
void Radeon_TheatreReadTVRegisters(
accelerator_info *ai, impactv_regs *values )
{
readTheatreRegList( ai, values, theatre_reg_mapping_start );
readTheatreRegList( ai, values, theatre_reg_mapping_finish );
//snooze( 1000000 );
}
// detect TV-Out encoder
void Radeon_DetectTVOut(
accelerator_info *ai )
{
shared_info *si = ai->si;
SHOW_FLOW0( 0, "" );
switch( si->tv_chip ) {
case tc_external_rt1: {
// for external encoder, we need the VIP channel
int channel = Radeon_FindVIPDevice( ai, THEATRE_ID );
if( channel < 0 ) {
SHOW_ERROR0( 2, "This card needs a Rage Theatre for TV-Out, but there is none." );
si->tv_chip = tc_none;
} else {
SHOW_INFO( 2, "Rage Theatre found on VIP channel %d", channel );
si->theatre_channel = channel;
}
break; }
default:
// for internal encoder, we don't have to look farther - it must be there
}
}
@@ -0,0 +1,61 @@
#include "radeon_accelerant.h"
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
// these are the official VESA modes
// interestingly, they completely differ from the modes generated via GMTF
const display_timing vesa_mode_list[] = {
{ 31500, 640, 672, 736, 832, 350, 382, 385, 445, B_POSITIVE_HSYNC}, /* Vesa_Monitor_@85Hz_(640X350X8.Z1) */
{ 31500, 640, 672, 736, 832, 400, 401, 404, 445, B_POSITIVE_VSYNC}, /* Vesa_Monitor_@85Hz_(640X400X8.Z1) */
{ 35500, 720, 756, 828, 936, 400, 401, 404, 446, B_POSITIVE_VSYNC}, /* Vesa_Monitor_@85Hz_(720X400X8.Z1) */
{ 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
{ 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, /* Vesa_Monitor_@72Hz_(640X480X8.Z1) */
{ 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
{ 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
{ 36000, 800, 824, 896, 1024, 600, 601, 603, 625, T_POSITIVE_SYNC}, /* Vesa_Monitor_800X600X56Hz - this is different to Be's mode! */
{ 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
{ 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, /* Vesa_Monitor_@72Hz_(800X600X8.Z1) */
{ 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
{ 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */
{ 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */
{ 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, /* Vesa_Monitor_@70_(1024X768X8.Z1) */
{ 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
{ 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
{ 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) - is this really Vesa? */
{ 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
{ 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) - is this really Vesa?*/
{ 108000, 1280, 1376, 1488, 1800, 960, 961, 964, 1000, T_POSITIVE_SYNC}, /* Vesa_Monitor_@60Hz_(1280X960X8.Z1) - not in Be's list */
{ 148500, 1280, 1344, 1504, 1728, 960, 961, 964, 1011, T_POSITIVE_SYNC}, /* Vesa_Monitor_@85Hz_(1280X960X8.Z1) - not in Be's list */
{ 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
{ 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
{ 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
{ 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */
{ 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */
{ 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */
{ 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */
{ 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) - is this really Vesa? */
{ 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
// the following modes weren't defined in Be's code (they are strange anyway - perhaps HDTV?)
{ 204800, 1792, 1920, 2120, 2448, 1344, 1345, 1348, 1394, B_POSITIVE_VSYNC}, /* Vesa_Monitor_@60Hz_(1792X1344X8.Z1) */
{ 261000, 1792, 1888, 2104, 2456, 1344, 1345, 1348, 1417, B_POSITIVE_VSYNC}, /* Vesa_Monitor_@75Hz_(1792X1344X8.Z1) */
{ 218300, 1856, 1952, 2176, 2528, 1392, 1393, 1396, 1439, B_POSITIVE_VSYNC}, /* Vesa_Monitor_@60Hz_(1856X1392X8.Z1) */
{ 288000, 1856, 1984, 2208, 2560, 1392, 1393, 1396, 1500, B_POSITIVE_VSYNC}, /* Vesa_Monitor_@75Hz_(1856X1392X8.Z1) */
{ 234000, 1920, 2048, 2256, 2600, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, /* Vesa_Monitor_@60Hz_(1920X1440X8.Z1) */
{ 297000, 1920, 2064, 2288, 2640, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, /* Vesa_Monitor_@75Hz_(1920X1440X8.Z1) */
};
// number of VESA modes
const size_t vesa_mode_list_count = sizeof( vesa_mode_list ) / sizeof( vesa_mode_list[0] );
@@ -217,7 +217,7 @@ void Radeon_ResetEngine( device_info *di )
// cannot be read out)
// -> this is a very bad idea, especially when it comes to laptops
// I comment it out for now, let's hope noone takes notice
if( di->num_heads > 1 ) {
if( di->num_crtc > 1 ) {
Radeon_OUTPLLP( regs, di->asic, RADEON_SCLK_CNTL,
RADEON_CP_MAX_DYN_STOP_LAT |
RADEON_SCLK_FORCEON_MASK,
@@ -342,6 +342,16 @@ static void loadMicroEngineRAMData( device_info *di )
Radeon_WaitForIdle( di, false, false );
/*
// HACK start
Radeon_ResetEngine( di );
OUTREG( di->regs, 0x30, 0x5133a3a0 ); // bus_cntl
OUTREGP( di->regs, 0xf0c, 0xff00, ~0xff ); // latency
Radeon_WaitForIdle( di, false, false );
Radeon_ResetEngine( di );
// HACK end
*/
OUTREG( di->regs, RADEON_CP_ME_RAM_ADDR, 0 );
for ( i = 0 ; i < 256 ; i++ ) {
@@ -401,7 +411,7 @@ static status_t initRingBuffer( device_info *di, int aring_size )
OUTREG( regs, RADEON_CP_RB_WPTR, 0 );
//*cp->ring.head = 0;
cp->ring.tail = 0;
return B_OK;
}
@@ -457,7 +467,7 @@ static status_t initCPFeedback( device_info *di )
*(uint32 *)MEM2CPU( cp->feedback.mem_type, cp->feedback.head_mem_offset) = 0;
memset( MEM2CPU( cp->feedback.mem_type, cp->feedback.scratch_mem_offset), 0, 0x40 );
//*cp->ring.head = 0;
return B_OK;
}
@@ -95,7 +95,7 @@ static status_t Radeon_PrepareDMA(
cur_size = min( contig_size, RADEON_DMA_DESC_MAX_SIZE );
if( ++num_desc > di->dma_desc_max_num ) {
if( ++num_desc > (int)di->dma_desc_max_num ) {
SHOW_ERROR( 2, "Overflow of DMA descriptors, %ld bytes left", size );
res = B_BAD_VALUE;
goto err;
@@ -167,7 +167,7 @@ static status_t initGATT( GART_info *gart )
// temporary area where we fill in the memory map (deleted below)
map_area = create_area("pci_gart_map_area", (void **)&map, B_ANY_ADDRESS, map_area_size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
dprintf("pci_gart_map_area: %d\n", map_area);
dprintf("pci_gart_map_area: %ld\n", map_area);
get_memory_map( gart->buffer.ptr, gart->buffer.size, map, map_count );
@@ -37,6 +37,7 @@
#define PCI_agp_status 4 /* Status register */
#define PCI_agp_status_rq_mask 0xff000000 /* Maximum number of requests - 1 */
#define PCI_agp_status_rq_shift 24
#define PCI_agp_status_sba 0x0200 /* Sideband addressing supported */
#define PCI_agp_status_64bit 0x0020 /* 64-bit addressing supported */
#define PCI_agp_status_fw 0x0010 /* FW transfers supported */
@@ -46,6 +47,7 @@
#define PCI_agp_command 8 /* Control register */
#define PCI_agp_command_rq_mask 0xff000000 /* Master: Maximum number of requests */
#define PCI_agp_command_rq_shift 24
#define PCI_agp_command_sba 0x0200 /* Sideband addressing enabled */
#define PCI_agp_command_agp 0x0100 /* Allow processing of AGP transactions */
#define PCI_agp_command_64bit 0x0020 /* Allow processing of 64-bit addresses */
@@ -64,7 +66,8 @@
// show AGP capabilities
static void show_agp_status( uint32 status )
{
SHOW_FLOW( 3, "Status (%08lx): %s%s%s%s%s%s", status,
SHOW_FLOW( 3, "Status (%08lx): Max Queue Depth=%ld %s%s%s%s%s%s", status,
(status & PCI_agp_status_rq_mask) >> PCI_agp_status_rq_shift,
(status & PCI_agp_status_sba) != 0 ? "Sideband addressing " : "",
(status & PCI_agp_status_64bit) != 0 ? "64-bit " : "",
(status & PCI_agp_status_fw) != 0 ? "FastWrite " : "",
@@ -77,7 +80,8 @@ static void show_agp_status( uint32 status )
// show AGP settings
static void show_agp_command( uint32 command )
{
SHOW_FLOW( 3, "Command (%08lx): %s%s%s%s%s%s%s", command,
SHOW_FLOW( 3, "Command (%08lx): Queue Depth=%ld %s%s%s%s%s%s%s", command,
(command & PCI_agp_command_rq_mask) >> PCI_agp_command_rq_shift,
(command & PCI_agp_command_sba) != 0 ? "Sideband addressing " : "",
(command & PCI_agp_command_agp) != 0 ? "AGP-Enabled " : "AGP-Disabled ",
(command & PCI_agp_command_64bit) != 0 ? "64-bit " : "",
@@ -142,11 +146,12 @@ int find_capability( pci_info *pcii, uint8 capability )
// fix invalid AGP settings
void Radeon_Fix_AGP()
void Radeon_Fix_AGP(void)
{
long pci_index;
pci_info pci_data, *pcii;
// start with all features enabled, queue depth bits must be 0
uint32 common_caps =
PCI_agp_status_sba | PCI_agp_status_64bit | PCI_agp_status_fw |
PCI_agp_status_rate4 | PCI_agp_status_rate2 | PCI_agp_status_rate1;
@@ -164,9 +169,9 @@ void Radeon_Fix_AGP()
{
int offset;
SHOW_FLOW( 3, "Checking bus %d, device %d, function %d (vendor_id=%04x, device_id=%04x):",
/*SHOW_FLOW( 3, "Checking bus %d, device %d, function %d (vendor_id=%04x, device_id=%04x):",
pcii->bus, pcii->device, pcii->function,
pcii->vendor_id, pcii->device_id );
pcii->vendor_id, pcii->device_id );*/
offset = find_capability( pcii, PCI_cap_id_agp );
@@ -186,6 +191,20 @@ void Radeon_Fix_AGP()
read_queue_depth = min( read_queue_depth, agp_status & PCI_agp_status_rq_mask );
}
}
// explicitely enable AGP - it's not part of status register
common_caps |= PCI_agp_command_agp;
// choose fastest transmission speed and disable lower ones
if( (common_caps & PCI_agp_status_rate4) != 0 )
common_caps &= ~(PCI_agp_status_rate2 | PCI_agp_status_rate1);
else if( (common_caps & PCI_agp_status_rate2) != 0 )
common_caps &= ~PCI_agp_status_rate1;
else if( (common_caps & PCI_agp_status_rate1) == 0 )
// no speed found - disable AGP
common_caps &= ~PCI_agp_command_agp;
common_caps |= read_queue_depth;
SHOW_FLOW0( 3, "Combined:" );
show_agp_command( common_caps );
@@ -204,7 +223,7 @@ void Radeon_Fix_AGP()
pcii->bus, pcii->device, pcii->function,
pcii->vendor_id, pcii->device_id );
set_pci( offset + PCI_agp_command, 4, common_caps | read_queue_depth );
set_pci( offset + PCI_agp_command, 4, common_caps );
}
}
}
@@ -466,7 +466,7 @@ static void Radeon_GetFPData( device_info *di )
}
// detect amount of graphics memory
void Radeon_DetectRAM( device_info *di )
static void Radeon_DetectRAM( device_info *di )
{
vuint8 *regs = di->regs;
@@ -66,10 +66,13 @@
#define DEVICE_ID_RADEON_Lf 0x4c66
#define DEVICE_ID_RADEON_Lg 0x4c67
// M9+
#define DEVICE_ID_RADEON_5c61 0x5c61
// RV280
#define DEVICE_ID_RADEON_Ya_ 0x5960
#define DEVICE_ID_RADEON_Ya 0x5961
#define DEVICE_ID_RADEON_Yd 0x5964
#define DEVICE_ID_RADEON_Zprea 0x5960
#define DEVICE_ID_RADEON_Za 0x5961
#define DEVICE_ID_RADEON_Zd 0x5964
// r300
#define DEVICE_ID_RADEON_ND 0x4e44
@@ -86,8 +89,11 @@
// rv350
#define DEVICE_ID_RADEON_AP 0x4150
#define DEVICE_ID_RADEON_AQ 0x4151
#define DEVICE_ID_RADEON_NO 0x4e50
#define DEVICE_ID_RADEON_NS 0x4e54
// m10
#define DEVICE_ID_RADEON_NP 0x4e50
// Mobility Fire GL T2 - any idea about the chip?
#define DEVICE_ID_RADEON_NT 0x4e54
// rv360
#define DEVICE_ID_RADEON_AR 0x4152
@@ -97,9 +103,6 @@
#define DEVICE_ID_RADEON_NH 0x4e48
#define DEVICE_ID_RADEON_NI 0x4e49
// Mobility Fire GL T2 - any idea about the chip?
#define DEVICE_ID_RADEON_NT 0x4e54
// r360
#define DEVICE_ID_RADEON_NJ 0x4e4a
@@ -131,8 +134,6 @@ RadeonDevice radeon_device_list[] = {
// mobility version of original Radeon (based on VE), now called M6
{ DEVICE_ID_RADEON_LY, rt_m6, "Radeon Mobility" },
{ DEVICE_ID_RADEON_LZ, rt_m6, "Radeon Mobility M6 LZ" },
// not sure about that: ROM signature is "RADEON" which means r100
{ DEVICE_ID_RADEON_NT, rt_m6, "Radeon Mobility FireGL T2" },
// rs100 (integrated Radeon, seems to be a Radeon VE)
{ DEVICE_ID_IGP320M, rt_rs100, "IGP320M" },
@@ -159,7 +160,7 @@ RadeonDevice radeon_device_list[] = {
{ DEVICE_ID_RADEON_Qk, rt_r200, "Radeon 8500 Qk" },
{ DEVICE_ID_RADEON_BB, rt_r200, "ALL-IN-Wonder Radeon 8500 DV" },
// RV250 (cut-down R200)
// RV250 (cut-down R200 with integrated TV-Out)
{ DEVICE_ID_RADEON_Id, rt_rv250, "Radeon 9000 Id" },
{ DEVICE_ID_RADEON_Ie, rt_rv250, "Radeon 9000 Ie" },
{ DEVICE_ID_RADEON_If, rt_rv250, "Radeon 9000" },
@@ -171,11 +172,14 @@ RadeonDevice radeon_device_list[] = {
{ DEVICE_ID_RADEON_Lf, rt_m9, "Radeon Mobility 9000 Lf" },
{ DEVICE_ID_RADEON_Lg, rt_m9, "Radeon Mobility 9000 Lg" },
// RV280
// the naming scheme can't properly handle this id
{ DEVICE_ID_RADEON_Ya_, rt_rv280, "Radeon 9200" },
{ DEVICE_ID_RADEON_Ya, rt_rv280, "Radeon 9200" },
{ DEVICE_ID_RADEON_Yd, rt_rv280, "Radeon 9200 SE" },
// RV280 (rv250 with higher frequency)
// this entry violates naming scheme, so it's probably wrong
{ DEVICE_ID_RADEON_Zprea, rt_rv280, "Radeon 9200" },
{ DEVICE_ID_RADEON_Za, rt_rv280, "Radeon 9200" },
{ DEVICE_ID_RADEON_Zd, rt_rv280, "Radeon 9200 SE" },
// M9+ (based on rv280)
{ DEVICE_ID_RADEON_5c61,rt_m9plus, "Radeon Mobility 9200" },
// R300
{ DEVICE_ID_RADEON_ND, rt_r300, "Radeon 9700 ND" },
@@ -187,13 +191,16 @@ RadeonDevice radeon_device_list[] = {
{ DEVICE_ID_RADEON_AE, rt_r300, "Radeon 9700 AE" },
{ DEVICE_ID_RADEON_AF, rt_r300, "Radeon 9700 AF" },
{ DEVICE_ID_RADEON_AG, rt_r300, "Radeon 9700 AG" },
// RV350
{ DEVICE_ID_RADEON_AP, rt_rv350, "Radeon 9600 AP" },
{ DEVICE_ID_RADEON_AQ, rt_rv350, "Radeon 9600 AQ" },
{ DEVICE_ID_RADEON_NO, rt_rv350, "Radeon 9600 Pro" },
{ DEVICE_ID_RADEON_NS, rt_rv350, "Mobility FireGL T2" },
// M10 (based on rv350)
{ DEVICE_ID_RADEON_NP, rt_m10, "Radeon Mobility 9600 NP" },
// not sure about that: ROM signature is "RADEON" which means r100
{ DEVICE_ID_RADEON_NT, rt_m10, "Radeon Mobility FireGL T2" },
// RV360 (probably minor revision of rv350)
{ DEVICE_ID_RADEON_AR, rt_rv360, "Radeon 9600 AR" },
@@ -205,10 +212,10 @@ RadeonDevice radeon_device_list[] = {
// R360 (probably minor revision of r350)
{ DEVICE_ID_RADEON_NJ, rt_r360, "Radeon 9800 XT" },
// rs100 (aka IGP)
// rs100 (aka IGP 320)
{ DEVICE_ID_IGP320M, rt_rs100, "Radeon IGP 320M" },
// rs200 (aka IGP)
// rs200 (aka IGP 340)
{ DEVICE_ID_RADEON_C7, rt_rs200, "IGP330M/340M/350M (U2) 4337" },
{ DEVICE_ID_RADEON_A7, rt_rs200, "IGP 340" },
@@ -278,26 +285,29 @@ static struct {
bool has_crtc2; // has second CRTC
bool is_mobility; // mobility chip
bool has_vip; // has VIP/I2C
bool new_pll; // reference divider of PPLL moved to other location
bool is_igp; // integrated graphics
} asic_properties[] =
{
{ "r100", tc_external_rt1, false, false, true, false }, // only original Radeons have one crtc only
{ "ve", tc_internal_rt1, true, false, true, false },
{ "m6", tc_internal_rt1, true, true, false, false },
{ "rs100", tc_internal_rt1, true, true, false, true },
{ "rv200", tc_internal_rt2, true, false, true, false },
{ "m7", tc_internal_rt1, true, true, false, false },
{ "rs200", tc_internal_rt1, true, true, false, true },
{ "r200", tc_external_rt1, true, false, true, false }, // r200 has external TV-Out encoder
{ "rv250", tc_internal_rt2, true, false, true, false },
{ "rv280", tc_internal_rt2, true, false, true, false },
{ "m9", tc_internal_rt2, true, true, true, false },
{ "r300", tc_internal_rt2, true, false, true, false },
{ "r300_4p",tc_internal_rt2, true, false, true, false },
{ "rv350", tc_internal_rt2, true, false, true, false },
{ "rv360", tc_internal_rt2, true, false, true, false },
{ "r350", tc_internal_rt2, true, false, true, false },
{ "r360", tc_internal_rt2, true, false, true, false }
{ "r100", tc_external_rt1, false, false, true, false, false }, // only original Radeons have one crtc only
{ "ve", tc_internal_rt1, true, false, true, false, false },
{ "m6", tc_internal_rt1, true, true, false, false, false },
{ "rs100", tc_internal_rt1, true, true, false, false, true },
{ "rv200", tc_internal_rt2, true, false, true, false, false },
{ "m7", tc_internal_rt1, true, true, false, false, false },
{ "rs200", tc_internal_rt1, true, true, false, false, true },
{ "r200", tc_external_rt1, true, false, true, false, false }, // r200 has external TV-Out encoder
{ "rv250", tc_internal_rt2, true, false, true, false, false },
{ "m9", tc_internal_rt2, true, true, false, false, false },
{ "rv280", tc_internal_rt2, true, false, true, false, false },
{ "m9plus", tc_internal_rt2, true, true, false, false, false },
{ "r300", tc_internal_rt2, true, false, true, true, false },
{ "r300_4p",tc_internal_rt2, true, false, true, true, false },
{ "rv350", tc_internal_rt2, true, false, true, true, false },
{ "m10", tc_internal_rt2, true, true, false, true, false },
{ "rv360", tc_internal_rt2, true, false, true, true, false },
{ "r350", tc_internal_rt2, true, false, true, true, false },
{ "r360", tc_internal_rt2, true, false, true, true, false }
};
@@ -318,11 +328,12 @@ static bool probeDevice( device_info *di )
if (device->device_id != di->pcii.device_id )
continue;
di->num_heads = asic_properties[device->asic].has_crtc2 ? 2 : 1;
di->num_crtc = asic_properties[device->asic].has_crtc2 ? 2 : 1;
di->tv_chip = asic_properties[device->asic].tv_chip;
di->asic = device->asic;
di->is_mobility = asic_properties[device->asic].is_mobility;
di->has_vip = asic_properties[device->asic].has_vip;
di->new_pll = asic_properties[device->asic].new_pll;
di->is_igp = asic_properties[device->asic].is_igp;
if( Radeon_MapBIOS( &di->pcii, &di->rom ) != B_OK )
@@ -289,8 +289,8 @@ static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len )
if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
result = Radeon_VIPRead( di, vr->channel, vr->address, &vr->data ) ?
B_OK : B_ERROR;
result = Radeon_VIPRead( di, vr->channel, vr->address, &vr->data,
vr->lock ) ? B_OK : B_ERROR;
} break;
case RADEON_VIPWRITE: {
@@ -299,8 +299,8 @@ static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len )
if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
result = Radeon_VIPWrite( di, vw->channel, vw->address, vw->data ) ?
B_OK : B_ERROR;
result = Radeon_VIPWrite( di, vw->channel, vw->address, vw->data,
vw->lock ) ? B_OK : B_ERROR;
} break;
case RADEON_FINDVIPDEVICE: {
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon kernel driver
@@ -213,9 +213,9 @@ status_t Radeon_FirstOpen( device_info *di )
memset( di->si, 0, sizeof( *di->si ));
si = di->si;
#ifdef ENABLE_LOGGING
#ifdef LOG_INCLUDE_STARTUP
#ifdef LOG_INCLUDE_STARTUP
si->log = log_init( 1000000 );
#endif
#endif
@@ -228,6 +228,7 @@ status_t Radeon_FirstOpen( device_info *di )
si->asic = di->asic;
si->is_mobility = di->is_mobility;
si->tv_chip = di->tv_chip;
si->new_pll = di->new_pll;
// detecting theatre channel in kernel would lead to code duplication,
// so we let the first accelerant take care of it
@@ -235,11 +236,11 @@ status_t Radeon_FirstOpen( device_info *di )
/* si->ports[0].disp_type = di->disp_type[0];
si->ports[1].disp_type = di->disp_type[1];*/
si->heads[0].is_crtc2 = false;
si->heads[0].flatpanel_port = 0;
si->heads[1].is_crtc2 = true;
si->heads[1].flatpanel_port = 1;
si->num_heads = di->num_heads;
si->crtc[0].crtc_idx = 0;
si->crtc[0].flatpanel_port = 0;
si->crtc[1].crtc_idx = 1;
si->crtc[1].flatpanel_port = 1;
si->num_crtc = di->num_crtc;
si->flatpanels[0] = di->fp_info;
si->pll = di->pll;
@@ -264,10 +265,11 @@ status_t Radeon_FirstOpen( device_info *di )
}
// currently, we assign fixed ports to this virtual card
di->vc->num_heads = si->num_heads;
di->vc->heads[0].physical_head = 0;
di->vc->heads[1].physical_head = 1;
di->vc->assigned_crtc[0] = true;
di->vc->assigned_crtc[1] = si->num_crtc > 1;
di->vc->controlled_displays =
dd_tv_crt | dd_crt | dd_lvds | dd_dvi | dd_ctv | dd_stv;
di->vc->fb_mem_handle = 0;
di->vc->cursor.mem_handle = 0;
@@ -324,6 +326,10 @@ status_t Radeon_FirstOpen( device_info *di )
// no AGP support
di->memmgr[mt_AGP] = NULL;
// fix AGP settings for IGP chipset
if( di->asic == rt_rs100 || di->asic == rt_rs200 )
Radeon_Fix_AGP();
// time to init Command Processor
result = Radeon_InitCP( di );
@@ -334,8 +340,6 @@ status_t Radeon_FirstOpen( device_info *di )
if( result != B_OK )
goto err0;
//Radeon_Fix_AGP();
// mem_alloc( di->local_memmgr, 0x100000, (void *)-1, &dma_block, &dma_offset );
/* dma_offset = 15 * 1024 * 1024;
@@ -391,7 +395,7 @@ void Radeon_LastClose( device_info *di )
Radeon_UnmapDevice(di);
#ifdef ENABLE_LOGGING
#ifdef LOG_INCLUDE_STARTUP
#ifdef LOG_INCLUDE_STARTUP
log_exit( di->si->log );
#endif
#endif
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon kernel driver
@@ -32,27 +32,27 @@ Radeon_ThreadInterruptWork( vuint8 *regs, device_info *di, uint32 int_status )
uint32 handled = B_HANDLED_INTERRUPT;
if( (int_status & RADEON_CRTC_VBLANK_STAT) != 0 &&
si->heads[0].vblank >= 0 )
si->crtc[0].vblank >= 0 )
{
int32 blocked;
++di->vbi_count[0];
if( (get_sem_count( si->heads[0].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
release_sem_etc( si->heads[0].vblank, -blocked, B_DO_NOT_RESCHEDULE );
if( (get_sem_count( si->crtc[0].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
release_sem_etc( si->crtc[0].vblank, -blocked, B_DO_NOT_RESCHEDULE );
handled = B_INVOKE_SCHEDULER;
}
}
if( (int_status & RADEON_CRTC2_VBLANK_STAT) != 0 &&
si->heads[1].vblank >= 0 )
si->crtc[1].vblank >= 0 )
{
int32 blocked;
++di->vbi_count[1];
if( (get_sem_count( si->heads[1].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
release_sem_etc( si->heads[1].vblank, -blocked, B_DO_NOT_RESCHEDULE );
if( (get_sem_count( si->crtc[1].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
release_sem_etc( si->crtc[1].vblank, -blocked, B_DO_NOT_RESCHEDULE );
handled = B_INVOKE_SCHEDULER;
}
}
@@ -166,7 +166,7 @@ static int32 timer_interrupt_func( timer *te )
/* do the things we do when we notice a vertical retrace */
result = Radeon_ThreadInterruptWork( regs, di,
RADEON_CRTC_VBLANK_STAT |
(di->num_heads > 1 ? RADEON_CRTC2_VBLANK_STAT : 0 ));
(di->num_crtc > 1 ? RADEON_CRTC2_VBLANK_STAT : 0 ));
}
/* pick the "other" timer */
@@ -198,21 +198,21 @@ Radeon_SetupIRQ( device_info *di, char *buffer )
sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 1",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
si->heads[0].vblank = create_sem( 0, buffer );
if( si->heads[0].vblank < 0 ) {
result = si->heads[0].vblank;
si->crtc[0].vblank = create_sem( 0, buffer );
if( si->crtc[0].vblank < 0 ) {
result = si->crtc[0].vblank;
goto err1;
}
si->heads[1].vblank = 0;
si->crtc[1].vblank = 0;
if( di->num_heads > 1 ) {
if( di->num_crtc > 1 ) {
sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 2",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
si->heads[1].vblank = create_sem( 0, buffer );
if( si->heads[1].vblank < 0 ) {
result = si->heads[1].vblank;
si->crtc[1].vblank = create_sem( 0, buffer );
if( si->crtc[1].vblank < 0 ) {
result = si->crtc[1].vblank;
goto err2;
}
}
@@ -241,9 +241,9 @@ Radeon_SetupIRQ( device_info *di, char *buffer )
/* this is required because apps can't aquire kernel semaphores */
thid = find_thread(NULL);
get_thread_info(thid, &thinfo);
set_sem_owner(si->heads[0].vblank, thinfo.team);
if( di->num_heads > 1 )
set_sem_owner(si->heads[1].vblank, thinfo.team);
set_sem_owner(si->crtc[0].vblank, thinfo.team);
if( di->num_crtc > 1 )
set_sem_owner(si->crtc[1].vblank, thinfo.team);
//set_sem_owner(di->cap_sem, thinfo.team);
/* disable all interrupts */
@@ -283,10 +283,10 @@ err5:
err4:
delete_sem( di->cap_sem );
err3:
if( di->num_heads > 1 )
delete_sem( si->heads[1].vblank );
if( di->num_crtc > 1 )
delete_sem( si->crtc[1].vblank );
err2:
delete_sem( si->heads[0].vblank );
delete_sem( si->crtc[0].vblank );
err1:
return result;
}
@@ -313,13 +313,13 @@ Radeon_CleanupIRQ( device_info *di )
remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, Radeon_Interrupt, di);
}
delete_sem( si->heads[0].vblank );
delete_sem( si->crtc[0].vblank );
if( di->num_heads > 1 )
delete_sem( si->heads[1].vblank );
if( di->num_crtc > 1 )
delete_sem( si->crtc[1].vblank );
delete_sem( di->cap_sem );
delete_sem( di->dma_sem );
di->cap_sem = si->heads[1].vblank = si->heads[0].vblank = 0;
di->cap_sem = si->crtc[1].vblank = si->crtc[0].vblank = 0;
}
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon kernel driver
@@ -106,11 +106,12 @@ typedef struct device_info {
vuint8 *regs;
radeon_type asic;
uint8 num_heads;
uint8 num_crtc;
tv_chip_type tv_chip;
bool is_mobility;
bool is_igp;
bool new_pll;
bool has_vip;
bool is_igp;
//display_type_e disp_type[2];
fp_info fp_info;
@@ -202,7 +203,7 @@ void Radeon_CleanupIRQ( device_info *di );
// agp.c
void Radeon_Fix_AGP();
void Radeon_Fix_AGP(void);
// mem_controller.c
@@ -218,8 +219,8 @@ void Radeon_UninitCP( device_info *di );
// vip.c
bool Radeon_VIPRead( device_info *di, uint channel, uint address, uint32 *data );
bool Radeon_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data );
bool Radeon_VIPRead( device_info *di, uint channel, uint address, uint32 *data, bool lock );
bool Radeon_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data, bool lock );
int Radeon_FindVIPDevice( device_info *di, uint32 device_id );
@@ -1,5 +1,5 @@
/*
Copyright (c) 2002-04, Thomas Kurschel
Copyright (c) 2002-05, Thomas Kurschel
Part of Radeon accelerant
@@ -25,7 +25,8 @@ static bool Radeon_VIPWaitForIdle( device_info *di );
// read data from VIP
// CP lock must be hold
static bool do_VIPRead( device_info *di, uint channel, uint address, uint32 *data )
static bool do_VIPRead(
device_info *di, uint channel, uint address, uint32 *data )
{
vuint8 *regs = di->regs;
@@ -74,21 +75,28 @@ static bool do_VIPRead( device_info *di, uint channel, uint address, uint32 *dat
}
// public function: read data from VIP
bool Radeon_VIPRead( device_info *di, uint channel, uint address, uint32 *data )
bool Radeon_VIPRead(
device_info *di, uint channel, uint address, uint32 *data, bool lock )
{
bool res;
ACQUIRE_BEN( di->si->cp.lock );
if( lock )
ACQUIRE_BEN( di->si->cp.lock );
res = do_VIPRead( di, channel, address, data );
RELEASE_BEN( di->si->cp.lock );
if( lock )
RELEASE_BEN( di->si->cp.lock );
//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
return res;
}
// write data to VIP
// not must be hold
static bool do_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
// CP must be hold
static bool do_VIPWrite(
device_info *di, uint8 channel, uint address, uint32 data )
{
vuint8 *regs = di->regs;
bool res;
@@ -110,25 +118,33 @@ static bool do_VIPWrite( device_info *di, uint8 channel, uint address, uint32 da
}
// public function: write data to VIP
bool Radeon_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
bool Radeon_VIPWrite(
device_info *di, uint8 channel, uint address, uint32 data, bool lock )
{
bool res;
ACQUIRE_BEN( di->si->cp.lock );
//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
if( lock )
ACQUIRE_BEN( di->si->cp.lock );
res = do_VIPWrite( di, channel, address, data );
RELEASE_BEN( di->si->cp.lock );
if( lock )
RELEASE_BEN( di->si->cp.lock );
return res;
}
// reset VIP
static void VIPReset( device_info *di )
static void VIPReset(
device_info *di, bool lock )
{
vuint8 *regs = di->regs;
ACQUIRE_BEN( di->si->cp.lock );
if( lock )
ACQUIRE_BEN( di->si->cp.lock );
Radeon_WaitForFifo( di, 5 );
OUTREG( regs, RADEON_VIPH_CONTROL,
@@ -151,44 +167,15 @@ static void VIPReset( device_info *di )
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH3_CHUNK_SHIFT));
OUTREGP( regs, RADEON_TEST_DEBUG_CNTL, 0, ~RADEON_TEST_DEBUG_CNTL_OUT_EN );
RELEASE_BEN( di->si->cp.lock );
}
// find VIP channel of a device
// return: >= 0 channel of device
// < 0 no device found
int Radeon_FindVIPDevice( device_info *di, uint32 device_id )
{
uint channel;
uint32 cur_device_id;
// if card has no VIP port, let hardware detection fail;
// in this case, noone will bother us again
if( !di->has_vip )
return -1;
VIPReset( di );
// there are up to 4 devices, connected to one of 4 channels
for( channel = 0; channel < 4; ++channel ) {
// read device id
if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id ))
continue;
// compare device id directly
if( cur_device_id == device_id )
return channel;
}
// couldn't find device
return -1;
if( lock )
RELEASE_BEN( di->si->cp.lock );
}
// check whether VIP host is idle
// lock must be hold
static status_t Radeon_VIPIdle( device_info *di )
static status_t Radeon_VIPIdle(
device_info *di )
{
vuint8 *regs = di->regs;
uint32 timeout;
@@ -218,7 +205,8 @@ static status_t Radeon_VIPIdle( device_info *di )
// wait until VIP host is idle
// lock must be hold
static bool Radeon_VIPWaitForIdle( device_info *di )
static bool Radeon_VIPWaitForIdle(
device_info *di )
{
int i;
@@ -239,3 +227,42 @@ static bool Radeon_VIPWaitForIdle( device_info *di )
return false;
}
// find VIP channel of a device
// return: >= 0 channel of device
// < 0 no device found
int Radeon_FindVIPDevice(
device_info *di, uint32 device_id )
{
uint channel;
uint32 cur_device_id;
// if card has no VIP port, let hardware detection fail;
// in this case, noone will bother us again
if( !di->has_vip )
return -1;
ACQUIRE_BEN( di->si->cp.lock );
VIPReset( di, false );
// there are up to 4 devices, connected to one of 4 channels
for( channel = 0; channel < 4; ++channel ) {
// read device id
if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id, false ))
continue;
// compare device id directly
if( cur_device_id == device_id ) {
RELEASE_BEN( di->si->cp.lock );
return channel;
}
}
RELEASE_BEN( di->si->cp.lock );
// couldn't find device
return -1;
}