From e02e12de8ae0968a8772190f7ebbfb4b35d26e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 1 Apr 2005 14:16:38 +0000 Subject: [PATCH] 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 --- .../private/graphics/radeon/accelerant_ext.h | 7 +- headers/private/graphics/radeon/crtc_regs.h | 23 - headers/private/graphics/radeon/dac_regs.h | 41 +- .../private/graphics/radeon/memcntrl_regs.h | 23 + headers/private/graphics/radeon/multimon.h | 8 + headers/private/graphics/radeon/pll_regs.h | 6 +- .../graphics/radeon/radeon_interface.h | 206 +---- headers/private/graphics/radeon/radeon_regs.h | 4 +- .../private/graphics/radeon/theatre_regs.h | 18 + headers/private/graphics/radeon/tv_out_regs.h | 56 +- headers/private/graphics/radeon/version.h | 2 +- src/add-ons/accelerants/radeon/CP.c | 2 +- src/add-ons/accelerants/radeon/Cursor.c | 101 +-- src/add-ons/accelerants/radeon/GetModeInfo.c | 9 +- .../accelerants/radeon/InitAccelerant.c | 8 +- src/add-ons/accelerants/radeon/Jamfile | 9 +- .../accelerants/radeon/ProposeDisplayMode.c | 51 +- .../accelerants/radeon/SetDisplayMode.c | 266 ++++--- src/add-ons/accelerants/radeon/crtc.c | 113 +-- src/add-ons/accelerants/radeon/dpms.c | 190 +++-- .../accelerants/radeon/driver_wrapper.c | 2 + src/add-ons/accelerants/radeon/flat_panel.c | 55 +- .../radeon/{tv_out.c => impactv.c} | 753 ++++++++++-------- .../accelerants/radeon/internal_tv_out.c | 272 +++++++ .../accelerants/radeon/monitor_detection.c | 397 +++++++-- .../accelerants/radeon/monitor_routing.c | 676 +++++++++++++--- src/add-ons/accelerants/radeon/multimon.c | 182 +++-- src/add-ons/accelerants/radeon/overlay.c | 126 +-- src/add-ons/accelerants/radeon/palette.c | 33 +- src/add-ons/accelerants/radeon/pll.c | 145 ++-- .../accelerants/radeon/radeon_accelerant.h | 100 +-- src/add-ons/accelerants/radeon/set_mode.h | 280 +++++++ src/add-ons/accelerants/radeon/settings.cpp | 40 +- src/add-ons/accelerants/radeon/theatre_out.c | 270 +++++++ src/add-ons/accelerants/radeon/vesa_modes.c | 61 ++ .../kernel/drivers/graphics/radeon/CP_setup.c | 16 +- .../kernel/drivers/graphics/radeon/DMA.c | 2 +- .../kernel/drivers/graphics/radeon/PCI_GART.c | 2 +- .../kernel/drivers/graphics/radeon/agp.c | 31 +- .../kernel/drivers/graphics/radeon/bios.c | 2 +- .../kernel/drivers/graphics/radeon/detect.c | 89 ++- .../kernel/drivers/graphics/radeon/driver.c | 8 +- .../kernel/drivers/graphics/radeon/init.c | 34 +- .../kernel/drivers/graphics/radeon/irq.c | 52 +- .../drivers/graphics/radeon/radeon_driver.h | 13 +- .../kernel/drivers/graphics/radeon/vip.c | 123 +-- 46 files changed, 3357 insertions(+), 1550 deletions(-) rename src/add-ons/accelerants/radeon/{tv_out.c => impactv.c} (51%) create mode 100644 src/add-ons/accelerants/radeon/internal_tv_out.c create mode 100644 src/add-ons/accelerants/radeon/set_mode.h create mode 100644 src/add-ons/accelerants/radeon/theatre_out.c create mode 100644 src/add-ons/accelerants/radeon/vesa_modes.c diff --git a/headers/private/graphics/radeon/accelerant_ext.h b/headers/private/graphics/radeon/accelerant_ext.h index ed6b1aba1a..979a6ef83e 100644 --- a/headers/private/graphics/radeon/accelerant_ext.h +++ b/headers/private/graphics/radeon/accelerant_ext.h @@ -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; diff --git a/headers/private/graphics/radeon/crtc_regs.h b/headers/private/graphics/radeon/crtc_regs.h index e99ae6e502..e078f1350b 100644 --- a/headers/private/graphics/radeon/crtc_regs.h +++ b/headers/private/graphics/radeon/crtc_regs.h @@ -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 diff --git a/headers/private/graphics/radeon/dac_regs.h b/headers/private/graphics/radeon/dac_regs.h index a67d4bc137..76fbf7715e 100644 --- a/headers/private/graphics/radeon/dac_regs.h +++ b/headers/private/graphics/radeon/dac_regs.h @@ -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) diff --git a/headers/private/graphics/radeon/memcntrl_regs.h b/headers/private/graphics/radeon/memcntrl_regs.h index a413284206..337699f3e4 100644 --- a/headers/private/graphics/radeon/memcntrl_regs.h +++ b/headers/private/graphics/radeon/memcntrl_regs.h @@ -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 diff --git a/headers/private/graphics/radeon/multimon.h b/headers/private/graphics/radeon/multimon.h index b9d043ef64..fbc57a39ef 100644 --- a/headers/private/graphics/radeon/multimon.h +++ b/headers/private/graphics/radeon/multimon.h @@ -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 diff --git a/headers/private/graphics/radeon/pll_regs.h b/headers/private/graphics/radeon/pll_regs.h index 3e88bef392..a59d19ea19 100644 --- a/headers/private/graphics/radeon/pll_regs.h +++ b/headers/private/graphics/radeon/pll_regs.h @@ -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 diff --git a/headers/private/graphics/radeon/radeon_interface.h b/headers/private/graphics/radeon/radeon_interface.h index fe7fd2549b..6bd95870ab 100644 --- a/headers/private/graphics/radeon/radeon_interface.h +++ b/headers/private/graphics/radeon/radeon_interface.h @@ -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 diff --git a/headers/private/graphics/radeon/radeon_regs.h b/headers/private/graphics/radeon/radeon_regs.h index 291def6823..f2983f8a34 100644 --- a/headers/private/graphics/radeon/radeon_regs.h +++ b/headers/private/graphics/radeon/radeon_regs.h @@ -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 diff --git a/headers/private/graphics/radeon/theatre_regs.h b/headers/private/graphics/radeon/theatre_regs.h index b48eb0397a..23d60b32c6 100644 --- a/headers/private/graphics/radeon/theatre_regs.h +++ b/headers/private/graphics/radeon/theatre_regs.h @@ -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 diff --git a/headers/private/graphics/radeon/tv_out_regs.h b/headers/private/graphics/radeon/tv_out_regs.h index 6e4211e55a..eda2431e5a 100644 --- a/headers/private/graphics/radeon/tv_out_regs.h +++ b/headers/private/graphics/radeon/tv_out_regs.h @@ -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 diff --git a/headers/private/graphics/radeon/version.h b/headers/private/graphics/radeon/version.h index 97791bb862..23455a0711 100644 --- a/headers/private/graphics/radeon/version.h +++ b/headers/private/graphics/radeon/version.h @@ -8,4 +8,4 @@ */ // current version -#define RADEON_DRIVER_VERSION "Version: 4.1.0.0" +#define RADEON_DRIVER_VERSION "Version: 5.1.0.1" diff --git a/src/add-ons/accelerants/radeon/CP.c b/src/add-ons/accelerants/radeon/CP.c index 7cc60ed796..98330c7640 100644 --- a/src/add-ons/accelerants/radeon/CP.c +++ b/src/add-ons/accelerants/radeon/CP.c @@ -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; diff --git a/src/add-ons/accelerants/radeon/Cursor.c b/src/add-ons/accelerants/radeon/Cursor.c index ce00ecba94..f4f0bbae32 100644 --- a/src/add-ons/accelerants/radeon/Cursor.c +++ b/src/add-ons/accelerants/radeon/Cursor.c @@ -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 ); } } diff --git a/src/add-ons/accelerants/radeon/GetModeInfo.c b/src/add-ons/accelerants/radeon/GetModeInfo.c index ad60cdf44d..f461d1d42d 100644 --- a/src/add-ons/accelerants/radeon/GetModeInfo.c +++ b/src/add-ons/accelerants/radeon/GetModeInfo.c @@ -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; } diff --git a/src/add-ons/accelerants/radeon/InitAccelerant.c b/src/add-ons/accelerants/radeon/InitAccelerant.c index aa1b22a770..4d80bd85d8 100644 --- a/src/add-ons/accelerants/radeon/InitAccelerant.c +++ b/src/add-ons/accelerants/radeon/InitAccelerant.c @@ -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; diff --git a/src/add-ons/accelerants/radeon/Jamfile b/src/add-ons/accelerants/radeon/Jamfile index 07a0e531e8..0883205faf 100644 --- a/src/add-ons/accelerants/radeon/Jamfile +++ b/src/add-ons/accelerants/radeon/Jamfile @@ -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 : diff --git a/src/add-ons/accelerants/radeon/ProposeDisplayMode.c b/src/add-ons/accelerants/radeon/ProposeDisplayMode.c index 494f318ec7..637fa9b168 100644 --- a/src/add-ons/accelerants/radeon/ProposeDisplayMode.c +++ b/src/add-ons/accelerants/radeon/ProposeDisplayMode.c @@ -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 ) diff --git a/src/add-ons/accelerants/radeon/SetDisplayMode.c b/src/add-ons/accelerants/radeon/SetDisplayMode.c index fcd5ea6bfa..e838372265 100644 --- a/src/add-ons/accelerants/radeon/SetDisplayMode.c +++ b/src/add-ons/accelerants/radeon/SetDisplayMode.c @@ -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 +#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 // 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, ÷rs ); + else + dividers = tv_params->crt_dividers; + + Radeon_CalcPLLRegisters( mode, ÷rs, &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 ); diff --git a/src/add-ons/accelerants/radeon/crtc.c b/src/add-ons/accelerants/radeon/crtc.c index bf41012899..0f01669c1e 100644 --- a/src/add-ons/accelerants/radeon/crtc.c +++ b/src/add-ons/accelerants/radeon/crtc.c @@ -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 ); diff --git a/src/add-ons/accelerants/radeon/dpms.c b/src/add-ons/accelerants/radeon/dpms.c index 332941e54c..91b78420d7 100644 --- a/src/add-ons/accelerants/radeon/dpms.c +++ b/src/add-ons/accelerants/radeon/dpms.c @@ -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 ); } diff --git a/src/add-ons/accelerants/radeon/driver_wrapper.c b/src/add-ons/accelerants/radeon/driver_wrapper.c index 77b99d5025..c50a742fa5 100644 --- a/src/add-ons/accelerants/radeon/driver_wrapper.c +++ b/src/add-ons/accelerants/radeon/driver_wrapper.c @@ -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 )); } diff --git a/src/add-ons/accelerants/radeon/flat_panel.c b/src/add-ons/accelerants/radeon/flat_panel.c index 44139ec973..e09009ea69 100644 --- a/src/add-ons/accelerants/radeon/flat_panel.c +++ b/src/add-ons/accelerants/radeon/flat_panel.c @@ -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 ); } diff --git a/src/add-ons/accelerants/radeon/tv_out.c b/src/add-ons/accelerants/radeon/impactv.c similarity index 51% rename from src/add-ons/accelerants/radeon/tv_out.c rename to src/add-ons/accelerants/radeon/impactv.c index d0b8ab3858..c930681be7 100644 --- a/src/add-ons/accelerants/radeon/tv_out.c +++ b/src/add-ons/accelerants/radeon/impactv.c @@ -1,38 +1,40 @@ /* - Copyright (c) 2002/03, Thomas Kurschel + Copyright (c) 2002-04, Thomas Kurschel Part of Radeon accelerant - Programming of TV-out unit, both internal and Rage Theatre + ImpacTV programming. As this unit is contained in various chips, + the code to actually access the unit is separated. */ #include "radeon_interface.h" #include "radeon_accelerant.h" -#include "pll_regs.h" -#include "theatre_regs.h" #include "tv_out_regs.h" -#include "pll_access.h" #include "utils.h" -#include "stddef.h" +#include "set_mode.h" + +#include + // fixed-point resolution of UV scaler increment #define TV_UV_INC_FIX_SHIFT 14 #define TV_UV_INC_FIX_SCALE (1 << TV_UV_INC_FIX_SHIFT) -// fixed point resolution of UV scaler initialization +// fixed point resolution of UV scaler initialization (uv_accum_init) #define TV_UV_INIT_FIX_SHIFT 6 // calculate time when TV timing must be restarted -static void Radeon_CalcTVRestart( tv_params *params, const display_mode *mode, +static void Radeon_CalcImpacTVRestart( + impactv_params *params, const display_mode *mode, uint16 h_blank, uint16 f_total ) { uint32 h_first, v_first = 0, f_first; uint32 tmp_uv_accum_sum; uint16 uv_accum_frac, uv_accum_int; - uint line; + int line; uint32 how_early = 0; int32 first_num, restart_to_first_active_pixel_to_FIFO; uint32 time_to_active; @@ -44,12 +46,12 @@ static void Radeon_CalcTVRestart( tv_params *params, const display_mode *mode, tmp_uv_accum_sum = params->uv_accum_init << (TV_UV_INC_FIX_SHIFT - TV_UV_INIT_FIX_SHIFT); uv_accum_frac = tmp_uv_accum_sum & (TV_UV_INC_FIX_SCALE - 1); uv_accum_int = (tmp_uv_accum_sum >> TV_UV_INC_FIX_SHIFT) & 7; - + // at line disp + 18 the accumulator is initialized; // simulate timing during vertical blank and find the last CRT line where // a new TV line is started // (actually, I think this calculation is wrong) - for( line = mode->timing.v_display - 1 + 18; line < mode->timing.v_total; ++line ) { + for( line = mode->timing.v_display - 1 + 18; line < mode->timing.v_total - 2; ++line ) { if( uv_accum_int > 0 ) { --uv_accum_int; } else { @@ -60,7 +62,7 @@ static void Radeon_CalcTVRestart( tv_params *params, const display_mode *mode, } } - //SHOW_FLOW( 2, "f_first=%d, v_first=%d, h_first=%d", f_first, v_first, h_first ); + SHOW_FLOW( 3, "f_first=%d, v_first=%d, h_first=%d", f_first, v_first, h_first ); // theoretical time when restart should be started first_num = @@ -70,21 +72,31 @@ static void Radeon_CalcTVRestart( tv_params *params, const display_mode *mode, first_num += (how_early + TV_UV_INC_FIX_SCALE / 2) >> TV_UV_INC_FIX_SHIFT; + SHOW_FLOW( 3, "first_num=%d", first_num ); + // TV logic needs extra clocks to restart - time_to_active = params->tv_clocks_to_active + 3; + //params->tv_clocks_to_active = 0; + time_to_active = params->tv_clocks_to_active + 3; + + SHOW_FLOW( 3, "time_to_active=%d, crt_freq=%d, tv_freq=%d", + time_to_active, params->crt_dividers.freq, params->tv_dividers.freq ); // get delay until first bytes can be read from FIFO restart_to_first_active_pixel_to_FIFO = (int)( (int64)time_to_active * params->crt_dividers.freq / params->tv_dividers.freq - - (int64)(h_blank * params->crt_dividers.freq / params->tv_dividers.freq) / 2) + - (int64)h_blank * params->crt_dividers.freq / params->tv_dividers.freq / 2) - mode->timing.h_display / 2 + mode->timing.h_total / 2; // do restart a bit early to compensate delays first_num -= restart_to_first_active_pixel_to_FIFO; - SHOW_FLOW( 2, "restart_to_first_active_pixel_to_FIFO=%d", restart_to_first_active_pixel_to_FIFO ); + SHOW_FLOW( 3, "restart_to_first_active_pixel_to_FIFO=%d", restart_to_first_active_pixel_to_FIFO ); + + SHOW_FLOW( 3, "after delay compensation first_num=%d", first_num ); + + //first_num = 625592; // make restart time positive // ("%" operator doesn't like negative numbers) @@ -96,9 +108,12 @@ static void Radeon_CalcTVRestart( tv_params *params, const display_mode *mode, params->f_restart = (first_num / (mode->timing.v_total * mode->timing.h_total)) % f_total; first_num %= mode->timing.v_total * mode->timing.h_total; params->v_restart = (first_num / mode->timing.h_total) % mode->timing.v_total; - first_num %= mode->timing.v_total; + first_num %= mode->timing.h_total; params->h_restart = first_num; + /*params->v_restart = 623; + params->h_restart = 580;*/ + SHOW_FLOW( 2, "Restart in frame %d, line %d, pixel %d", params->f_restart, params->v_restart, params->h_restart ); } @@ -109,8 +124,8 @@ static int8 y_flicker_removal[5] = { 6, 5, 4, 3, 2 }; // associated filter parameters scaled by 8(!) static int8 y_saw_tooth_slope[5] = { 1, 2, 2, 4, 8 }; -static int8 y_coeff_value[5] = { 2, 2, 0, 4, 0 }; // these values are not scaled +static int8 y_coeff_value[5] = { 2, 2, 0, 4, 0 }; static bool y_coeff_enable[5] = { 1, 1, 0, 1, 0 }; #define countof( a ) (sizeof( (a) ) / sizeof( (a)[0] )) @@ -125,31 +140,41 @@ static bool y_coeff_enable[5] = { 1, 1, 0, 1, 0 }; // calculate flicker fixer parameters -static void Radeon_CalcTVFlickerFixer( tv_params *params ) +static void Radeon_CalcImpacTVFlickerFixer( + impactv_params *params ) { - int8 flicker_removal; + int flicker_removal; uint i; + int lower_border, upper_border; - // first, we determine how much flickering should be removed - // I reckon that we could tweak it a bit hear as only - // uv_inc <= flicker_removal < uv_inc * 2 - // must be assured - flicker_removal = (params->uv_inc + (TV_UV_INC_FIX_SCALE / 2)) >> TV_UV_INC_FIX_SHIFT; + // flicker_removal must be within [uv_inc..uv_inc*2); take care of fraction + lower_border = ((params->uv_inc + TV_UV_INC_FIX_SCALE - 1) >> TV_UV_INC_FIX_SHIFT); + upper_border = ((2 * params->uv_inc) >> TV_UV_INC_FIX_SHIFT); for( i = 0; i < countof( y_flicker_removal ); ++i ) { - if( flicker_removal == y_flicker_removal[i] ) + if( lower_border <= y_flicker_removal[i] && + upper_border > y_flicker_removal[i] ) break; } - // use most aggresive filtering if not in list - if( i > countof( y_flicker_removal )) + // use least aggresive filtering if not in list + if( i >= countof( y_flicker_removal )) i = countof( y_flicker_removal ) - 1; + flicker_removal = y_flicker_removal[i]; + + SHOW_FLOW( 3, "flicker removal=%d", flicker_removal ); + params->y_saw_tooth_slope = y_saw_tooth_slope[i] * (TV_SAW_FILTER_FIX_SCALE / 8); params->y_saw_tooth_amp = ((uint32)params->y_saw_tooth_slope * params->uv_inc) >> TV_UV_INC_FIX_SHIFT; - params->y_fall_accum_init = ((uint32)params->y_saw_tooth_slope * params->uv_accum_init) >> TV_UV_INC_FIX_SHIFT; - if( flicker_removal - (params->uv_inc >> TV_UV_INC_FIX_SHIFT) - < (params->uv_accum_init >> TV_UV_INIT_FIX_SHIFT)) + params->y_fall_accum_init = ((uint32)params->y_saw_tooth_slope * params->uv_accum_init) >> TV_UV_INIT_FIX_SHIFT; + + SHOW_FLOW( 3, "%d < %d ?", + (flicker_removal << 16) - ((int32)params->uv_inc << (16 - TV_UV_INC_FIX_SHIFT)), + ((int32)params->uv_accum_init << (16 - TV_UV_INIT_FIX_SHIFT)) ); + + if( (flicker_removal << 16) - ((int32)params->uv_inc << (16 - TV_UV_INC_FIX_SHIFT)) + < ((int32)params->uv_accum_init << (16 - TV_UV_INIT_FIX_SHIFT))) { params->y_rise_accum_init = (((flicker_removal << TV_UV_INIT_FIX_SHIFT) - params->uv_accum_init) * @@ -159,13 +184,15 @@ static void Radeon_CalcTVFlickerFixer( tv_params *params ) (((flicker_removal << TV_UV_INIT_FIX_SHIFT) - params->uv_accum_init - params->y_accum_init) * params->y_saw_tooth_slope) >> TV_UV_INIT_FIX_SHIFT; } + params->y_coeff_enable = y_coeff_enable[i]; params->y_coeff_value = y_coeff_value[i] * TV_Y_COEFF_FIX_SCALE / 8; } // correct sync position after tweaking total size -static void Radeon_AdoptSync( const display_mode *mode, display_mode *tweaked_mode ) +static void Radeon_AdoptSync( + const display_mode *mode, display_mode *tweaked_mode ) { uint16 h_over_plus, h_sync_width, tweaked_h_over_plus, @@ -197,20 +224,121 @@ static void Radeon_AdoptSync( const display_mode *mode, display_mode *tweaked_mo tweaked_mode->timing.v_sync_end = tweaked_mode->timing.v_sync_start + v_sync_width; } -#define TV_VERT_LEAD_IN_LINES 2 +static const uint16 hor_timing_NTSC[RADEON_TV_TIMING_SIZE] = { + // moved to left as much as possible + 0x0007, 0x003f, 0x0263, 0x0a24, 0x2a6b, 0x0a36, 0x126d-100, 0x1bfe, + 0x1a8f+100, 0x1ec7, 0x3863, 0x1bfe, 0x1bfe, 0x1a2a, 0x1e95, 0x0e31, + 0x201b, 0 +}; + +static const uint16 vert_timing_NTSC[RADEON_TV_TIMING_SIZE] = { + 0x2001, 0x200d, 0x1006, 0x0c06, 0x1006, 0x1818, 0x21e3, 0x1006, + 0x0c06, 0x1006, 0x1817, 0x21d4, 0x0002, 0 +}; + +static const uint16 hor_timing_PAL[RADEON_TV_TIMING_SIZE] = { + 0x0007, 0x0058, 0x027c, 0x0a31, 0x2a77, 0x0a95, 0x124f - 60, 0x1bfe, + 0x1b22 + 60, 0x1ef9, 0x387c, 0x1bfe, 0x1bfe, 0x1b31, 0x1eb5, 0x0e43, + 0x201b, 0 +}; + +static const uint16 vert_timing_PAL[RADEON_TV_TIMING_SIZE] = { + 0x2001, 0x200c, 0x1005, 0x0c05, 0x1005, 0x1401, 0x1821, 0x2240, + 0x1005, 0x0c05, 0x1005, 0x1401, 0x1822, 0x2230, 0x0002, 0 +}; + +static const uint16 *hor_timings[] = { + hor_timing_NTSC, + hor_timing_PAL, + hor_timing_NTSC, // palm: looks similar to NTSC, but differs slightly + hor_timing_NTSC, // palnc: looks a bit like NTSC, probably won't work + hor_timing_PAL, // scart pal + hor_timing_PAL // pal 60: horizontally, it is PAL +}; + +static const uint16 *vert_timings[] = { + vert_timing_NTSC, + vert_timing_PAL, + vert_timing_NTSC, // palm: vertically, this is PAL + vert_timing_PAL, // palnc: a bit like PAL, but not really + vert_timing_PAL, // scart pal + vert_timing_NTSC // pal 60: vertically, it is NTSC +}; + + +// timing of TV standards; +// the index is of type tv_standard +static const tv_timing radeon_std_tv_timing[6] = { + // TK: hand-tuned v_active_lines and horizontal zoom + {42954540, 2730, 200, 28, 200, 110, 2170, 525, 466/*440*/, 525, 2, 1, 0, 0.95/*0.88*/ * FIX_SCALE/2}, /* ntsc */ + // TK: frame_size_adjust was -6, but using 12 leads to perfect 25 Hz + {53203425, 3405, 250, 28, 320, 80, 2627, 625, 555/*498*/, 625, 2, 3, 12, 0.98/*0.91*/ * FIX_SCALE/2}, /* pal */ + {42907338, 2727, 200, 28, 200, 110, 2170, 525, 440, 525, 2, 1, 0, 0.91 * FIX_SCALE/2}, /* palm */ + {42984675, 2751, 202, 28, 202, 110, 2190, 625, 510, 625, 2, 3, 0, 0.91 * FIX_SCALE/2}, /* palnc */ + {53203425, 3405, 250, 28, 320, 80, 2627, 625, 498, 625, 2, 3, 0, 0.91 * FIX_SCALE/2}, /* scart pal ??? */ + {53203425, 3405, 250, 28, 320, 80, 2627, 525, 440, 525, 2, 1, 0, 0.91 * FIX_SCALE/2}, /* pal 60 */ +}; + + +// adjust timing so it fills the entire visible area; +// the result may not be CRT compatible! +static void Radeon_MakeOverscanMode( + display_timing *timing, tv_standard_e tv_format ) +{ + const tv_timing *tv_timing = &radeon_std_tv_timing[tv_format-1]; + + // vertical is easy: ratio of displayed lines and blank must be + // according to TV standard, having the sync delay of 1 line and + // sync len of 3 lines is used by most VESA modes + timing->v_total = timing->v_display * tv_timing->v_total / tv_timing->v_active_lines; + timing->v_sync_start = timing->v_display + 1; + timing->v_sync_end = timing->v_sync_start + 3; + + // horizontal is tricky: the ratio may not be important (as it's + // scaled by the TV-out unit anyway), but the sync position and length + // is pure guessing - VESA modes don't exhibit particular scheme + timing->h_total = timing->h_display * tv_timing->h_total / tv_timing->h_active_len; + timing->h_sync_start = min( timing->h_total * 30 / 1000, 2 * 8 ) + timing->h_display; + timing->h_sync_end = min( timing->h_total * 80 / 1000, 3 * 8 ) + timing->h_sync_start; + + // set some pixel clock - it's replaced during fine tuning anyway + timing->pixel_clock = timing->h_total * timing->v_total * 60; + // most (but not all) 60 Hz modes have all negative sync, so use that too + timing->flags = 0; + + SHOW_INFO0( 4, "got:" ); + SHOW_INFO( 4, "H: %4d %4d %4d %4d", + timing->h_display, timing->h_sync_start, + timing->h_sync_end, timing->h_total ); + SHOW_INFO( 4, "V: %4d %4d %4d %4d", + timing->v_display, timing->v_sync_start, + timing->v_sync_end, timing->v_total ); + SHOW_INFO( 4, "clk: %ld", timing->pixel_clock ); +} + + +#define TV_VERT_LEAD_IN_LINES 2 +#define TV_UV_ADR_INI 0xc8 // calculate TV parameters -void Radeon_CalcTVParams( const general_pll_info *general_pll, tv_params *params, - const tv_timing *tv_timing, bool internal_encoder, +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 ) { pll_info tv_pll, crt_pll; uint16 start_line, lines_before_active; + const tv_timing *tv_timing = &radeon_std_tv_timing[tv_format-1]; - SHOW_FLOW( 2, "internal_encoder=%s", internal_encoder ? "yes" : "no" ); + SHOW_FLOW( 2, "internal_encoder=%s, format=%d", + internal_encoder ? "yes" : "no", tv_format ); + + if( tv_format < ts_ntsc || tv_format > ts_max ) + tv_format = ts_ntsc; params->mode888 = true; + params->timing = *tv_timing; Radeon_GetTVPLLConfiguration( general_pll, &tv_pll, internal_encoder ); Radeon_CalcPLLDividers( &tv_pll, tv_timing->freq, 0, ¶ms->tv_dividers ); @@ -219,14 +347,16 @@ void Radeon_CalcTVParams( const general_pll_info *general_pll, tv_params *params // initially, we try to keep to requested mode *tweaked_mode = *mode; + + Radeon_MakeOverscanMode( &tweaked_mode->timing, tv_format ); // tweak CRT mode if necessary to match TV frame timing Radeon_MatchCRTPLL( &crt_pll, tv_timing->v_total, tv_timing->h_total, tv_timing->frame_size_adjust, tv_timing->freq, - mode, 2, 40, - internal_encoder ? 6 : 0, 2 + params->mode888, + tweaked_mode, 2, 40, + internal_encoder ? 0/*6*/ : 0, 2 + params->mode888, ¶ms->crt_dividers, tweaked_mode ); // adopt synchronization to make tweaked mode look like original mode @@ -242,39 +372,42 @@ void Radeon_CalcTVParams( const general_pll_info *general_pll, tv_params *params lines_before_active = (tv_timing->v_field_total - tv_timing->v_active_lines) / 2 - 1 - TV_VERT_LEAD_IN_LINES + 1; + + SHOW_FLOW( 3, "lines_before_active=%d, start_line=%d", lines_before_active, start_line ); params->tv_clocks_to_active = (uint32)lines_before_active * tv_timing->h_total + start_line; // calculate scaling. - // this must be done CalcTVRestart() or TVFlickerFixer() is called + // this must be done before CalcTVRestart() or TVFlickerFixer() is called // start accumulator always with 0.25 params->uv_accum_init = 0x10; // this value seems to be fixed (it's not written to any register but used // at some calculations) params->y_accum_init = 0; // for scaling ratio, take care that v_field_total is for full, not for half frames, - // therefore we devide it v_field_total by 2 + // therefore we devide v_field_total by 2 params->uv_inc = (tweaked_mode->timing.v_total << TV_UV_INC_FIX_SHIFT) * 2 / tv_timing->v_field_total; + + SHOW_FLOW( 3, "uv_inc=%d", params->uv_inc ); + params->h_inc = ((int64)tweaked_mode->timing.h_display * 4096 / - (tv_timing->h_active_len + tv_timing->h_active_delay) << FIX_SHIFT) / tv_timing->scale; + (tv_timing->h_active_len + tv_timing->h_active_delay) << (FIX_SHIFT - 1)) / tv_timing->scale; - Radeon_CalcTVRestart( params, tweaked_mode, + Radeon_CalcImpacTVRestart( params, tweaked_mode, tv_timing->h_total - tv_timing->h_active_len, tv_timing->f_total ); - Radeon_CalcTVFlickerFixer( params ); + Radeon_CalcImpacTVFlickerFixer( params ); } -// timing of TV standards; -// the index is of type tv_standard -tv_timing Radeon_std_tv_timing[6] = { - {42954540, 2730, 200, 28, 200, 110, 2170, 525, 440, 525, 2, 1, 0, 0.88 * FIX_SCALE}, /* ntsc */ - {53203425, 3405, 250, 28, 320, 80, 2627, 625, 498, 625, 2, 3, -6, 0.91 * FIX_SCALE}, /* pal */ - {42907338, 2727, 200, 28, 200, 110, 2170, 525, 440, 525, 2, 1, 0, 0.91 * FIX_SCALE}, /* palm */ - {42984675, 2751, 202, 28, 202, 110, 2190, 625, 510, 625, 2, 3, 0, 0.91 * FIX_SCALE}, /* palnc */ - {53203425, 3405, 250, 28, 320, 80, 2627, 625, 498, 625, 2, 3, 0, 0.91 * FIX_SCALE}, /* scart pal ??? */ - {53203425, 3405, 250, 28, 320, 80, 2627, 525, 440, 525, 2, 1, 0, 0.91 * FIX_SCALE}, /* pal 60 */ +// standard upsample coefficients (external Theatre only) +static uint32 std_upsample_filter_coeff[RADEON_TV_UPSAMP_COEFF_NUM] = { + 0x3f010000, 0x7b008002, 0x00003f01, + 0x341b7405, 0x7f3a7617, 0x00003d04, + 0x2d296c0a, 0x0e316c2c, 0x00003e7d, + 0x2d1f7503, 0x2927643b, 0x0000056f, + 0x29257205, 0x25295050, 0x00000572 }; @@ -282,21 +415,30 @@ tv_timing Radeon_std_tv_timing[6] = { // as TV-Out uses a CRTC, it reprograms a PLL to create an unscaled image; // as a result, you must not call Radeon_CalcPLLRegisters() afterwards // TBD: what's special in terms of PLL in TV-Out 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_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 ) { - // some register's content isn't created from scratch but - // only modified, so we need the original content first - Radeon_ReadTVRegisters( ai, values, internal_encoder ); + const tv_timing *timing = ¶ms->timing; + + SHOW_FLOW0( 2, "" ); + + if( tv_format < ts_ntsc || tv_format > ts_max ) + tv_format = ts_ntsc; values->tv_ftotal = timing->f_total; + // RE: UV_THINNER should affect sharpness only, but the only effect is that + // the colour fades out, so I leave it zero + values->tv_vscaler_cntl1 = RADEON_TV_VSCALER_CNTL1_Y_W_EN; + values->tv_vscaler_cntl1 = (values->tv_vscaler_cntl1 & 0xe3ff0000) | params->uv_inc; if( internal_encoder ) { + // RE: was on - update: disabling it breaks restart values->tv_vscaler_cntl1 |= RADEON_TV_VSCALER_CNTL1_RESTART_FIELD; if( mode->timing.h_display == 1024 ) values->tv_vscaler_cntl1 |= 4 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT; @@ -320,13 +462,18 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing params->y_rise_accum_init | RADEON_TV_Y_RISE_CNTL_Y_RISE_PING_PONG; + // RE: all dither flags/values were zero values->tv_vscaler_cntl2 = - (values->tv_vscaler_cntl2 & 0x00ffffff) | - RADEON_TV_VSCALER_CNTL2_DITHER_MODE | - RADEON_TV_VSCALER_CNTL2_Y_OUTPUT_DITHER_EN | - RADEON_TV_VSCALER_CNTL2_UV_OUTPUT_DITHER_EN | - RADEON_TV_VSCALER_CNTL2_UV_TO_BUF_DITHER_EN | + (values->tv_vscaler_cntl2 & 0x00fffff0) | (params->uv_accum_init << RADEON_TV_VSCALER_CNTL2_UV_ACCUM_INIT_SHIFT); + + if( internal_encoder ) { + values->tv_vscaler_cntl2 |= + RADEON_TV_VSCALER_CNTL2_DITHER_MODE | + RADEON_TV_VSCALER_CNTL2_Y_OUTPUT_DITHER_EN | + RADEON_TV_VSCALER_CNTL2_UV_OUTPUT_DITHER_EN | + RADEON_TV_VSCALER_CNTL2_UV_TO_BUF_DITHER_EN; + } values->tv_hrestart = params->h_restart; values->tv_vrestart = params->v_restart; @@ -340,9 +487,11 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing << RADEON_TV_PLL_CNTL_TV_M0_HI_SHIFT) | ((params->tv_dividers.feedback >> RADEON_TV_PLL_CNTL_TV_N0_LO_BITS) << RADEON_TV_PLL_CNTL_TV_N0_HI_SHIFT) | - RADEON_TV_PLL_CNTL_TV_SLIP_EN | - (params->tv_dividers.post << RADEON_TV_PLL_CNTL_TV_P_SHIFT) | - RADEON_TV_PLL_CNTL_TV_DTO_EN; + // RE: was on + //RADEON_TV_PLL_CNTL_TV_SLIP_EN | + (params->tv_dividers.post << RADEON_TV_PLL_CNTL_TV_P_SHIFT); //| + // RE: was on + //RADEON_TV_PLL_CNTL_TV_DTO_EN; values->tv_crt_pll_cntl = (params->crt_dividers.ref & RADEON_TV_CRT_PLL_CNTL_M0_LO_MASK) | ((params->crt_dividers.feedback & RADEON_TV_CRT_PLL_CNTL_N0_LO_MASK) @@ -353,10 +502,13 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing << RADEON_TV_CRT_PLL_CNTL_N0_HI_SHIFT) | (params->crt_dividers.extra_post == 2 ? RADEON_TV_CRT_PLL_CNTL_CLKBY2 : 0); + // TK: from Gatos + // in terms of byte clock devider, I have no clue how that works, + // but leaving it 1 seems to be save values->tv_clock_sel_cntl = - (values->tv_clock_sel_cntl & ~0x3d) | 0x33 | - ((params->crt_dividers.post_code - 1) << 2); + ((/*params->crt_dividers.post_code - 1*/0) << RADEON_TV_CLOCK_SEL_CNTL_BYTCLK_SHIFT) | + (1 << RADEON_TV_CLOCK_SEL_CNTL_BYTCLKD_SHIFT); values->tv_clkout_cntl = 0x09; if( !internal_encoder ) @@ -366,9 +518,10 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing values->tv_hsize = mode->timing.h_display; values->tv_hdisp = mode->timing.h_display - 1; values->tv_hstart = + // TK: was -12, but this cuts off the left border of the image internal_encoder ? - mode->timing.h_display - params->mode888 - 12 : - mode->timing.h_display - params->mode888 + 12; + values->tv_hdisp + 1 - params->mode888 + 12 : + values->tv_hdisp + 1 - params->mode888 + 12; values->tv_vtotal = mode->timing.v_total - 1; values->tv_vdisp = mode->timing.v_display - 1; @@ -387,23 +540,45 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing << RADEON_TV_TIMING_CNTL_UV_OUTPUT_POST_SCALE_SHIFT); } - values->feedback_div = params->crt_dividers.feedback; - values->post_div = params->crt_dividers.post; - values->ppll_ref_div = params->crt_dividers.ref; - values->ppll_div_3 = - params->crt_dividers.feedback | - (params->crt_dividers.post_code << 16); - values->htotal_cntl = mode->timing.h_total & 7; - if( internal_encoder ) { - values->tv_dac_cntl = - // TBD: DAC is always set to NTSC mode, though there is a PAL mode! + // tell TV-DAC to generate proper NTSC/PAL signal values->tv_dac_cntl = RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD | - RADEON_TV_DAC_CNTL_STD_NTSC/*RADEON_TV_DAC_CNTL_STD_PAL*/ | (8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) | (6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT); + + switch( tv_format ) { + case ts_ntsc: + values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_STD_NTSC; + break; + + case ts_pal_bdghi: + case ts_pal_m: + case ts_pal_nc: + case ts_scart_pal: + case ts_pal_60: + values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_STD_PAL; + break; + default: + } + + // enable composite or S-Video DAC + values->tv_dac_cntl |= + RADEON_TV_DAC_CNTL_RDACPD | + RADEON_TV_DAC_CNTL_GDACPD | + RADEON_TV_DAC_CNTL_BDACPD; + + if( (display_device & dd_ctv) != 0 ) { + values->tv_dac_cntl &= + ~RADEON_TV_DAC_CNTL_BDACPD; + } + + if( (display_device & dd_stv) != 0 ) { + values->tv_dac_cntl &= + ~(RADEON_TV_DAC_CNTL_RDACPD | + RADEON_TV_DAC_CNTL_GDACPD); + } } else { values->tv_dac_cntl = (values->tv_dac_cntl & ~(RADEON_TV_DAC_CNTL_STD_NTSC | 0x88 | @@ -413,16 +588,16 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing RADEON_TV_DAC_CNTL_NHOLD; } - values->tv_modulator_cntl1 = - values->tv_modulator_cntl1 & ~( - RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN | - RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | - RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_MASK | - RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_MASK); + values->tv_modulator_cntl1 &= ~( + RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN | + RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | + RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_MASK | + RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_MASK); switch( tv_format ) { case ts_ntsc: - values->tv_dac_cntl |= + // RE: typo? + //values->tv_dac_cntl |= values->tv_modulator_cntl1 |= RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | (0x46 << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) | @@ -432,7 +607,7 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing ((0 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT); break; - case ts_pal: + case ts_pal_bdghi: values->tv_modulator_cntl1 |= RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN | RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | @@ -456,32 +631,51 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing default: // there are many formats missing, sigh... } + + // RE: + values->tv_modulator_cntl1 |= + RADEON_TV_MODULATOR_CNTL1_YFLT_EN | + RADEON_TV_MODULATOR_CNTL1_UVFLT_EN | + RADEON_TV_MODULATOR_CNTL1_SLEW_RATE_LIMIT | + (2 << RADEON_TV_MODULATOR_CNTL1_CY_FILT_BLEND_SHIFT); - values->tv_data_delay_a = 0x0b0c0a06; - values->tv_data_delay_b = 0x070a0a0c; + if( internal_encoder ) { + values->tv_data_delay_a = 0x0b0c0a06; + values->tv_data_delay_b = 0x070a0a0c; + } else { + values->tv_data_delay_a = 0x07080604; + values->tv_data_delay_b = 0x03070607; + } - values->tv_frame_lock_cntl = internal_encoder ? 0 : 0xf; + values->tv_frame_lock_cntl = internal_encoder ? 0 : 0xf0f; if( internal_encoder ) { values->tv_pll_cntl1 = (4 << RADEON_TV_PLL_CNTL1_TVPCP_SHIFT) | (4 << RADEON_TV_PLL_CNTL1_TVPVG_SHIFT) | - (2 << RADEON_TV_PLL_CNTL1_TVPDC_SHIFT) | + // RE: was 2 + (1 << RADEON_TV_PLL_CNTL1_TVPDC_SHIFT) | RADEON_TV_PLL_CNTL1_TVCLK_SRC_SEL_TVPLLCLK | RADEON_TV_PLL_CNTL1_TVPLL_TEST; values->tv_rgb_cntl = - ((head->is_crtc2 ? 2 : 0) << RADEON_TV_RGB_CNTL_RGB_SRC_SEL_SHIFT) | + ((crtc_idx == 1 ? 2 : 0) << RADEON_TV_RGB_CNTL_RGB_SRC_SEL_SHIFT) | RADEON_TV_RGB_CNTL_RGB_DITHER_EN | (0xb << RADEON_TV_RGB_CNTL_UVRAM_READ_MARGIN_SHIFT) | (7 << RADEON_TV_RGB_CNTL_FIFORAM_FIFOMACRO_READ_MARGIN_SHIFT); + // RE: + values->tv_rgb_cntl |= 0x4000000; + values->tv_pre_dac_mux_cntl = RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN | RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN | RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN | - RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN | - (0x2c << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT); + RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN; + + // RE: + /* | + (0x2c << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/ } else { // this register seems to have completely different meaning on Theatre chip values->tv_pll_cntl1 = @@ -495,15 +689,18 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN | RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN | RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN | - RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN | - (0xaf << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT); + RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN; + // RE: + /*(0xaf << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/ } values->tv_pll_fine_cntl = 0; // TBD: this is certainly broken // (they do an ((orig & 0xe0) & 0x600) which is constant zero) - values->tv_master_cntl = 0; + values->tv_master_cntl = + RADEON_TV_MASTER_CNTL_CRT_FIFO_CE_EN | + RADEON_TV_MASTER_CNTL_TV_FIFO_CE_EN; if( tv_format == ts_ntsc ) values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX; @@ -511,269 +708,121 @@ void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing values->tv_master_cntl &= ~RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX; // this is missing in the sample code - values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_TV_ON; + if( internal_encoder ) + values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_TV_ON; + else + values->tv_master_cntl |= + RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX | // RE: guessed + + RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST | + RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST | + RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST; + + values->tv_gain_limit_settings = 0x017f05ff; + values->tv_linear_gain_settings = 0x01000100; + values->tv_upsamp_and_gain_cntl = 0x00000005; + values->tv_crc_cntl = 0; SHOW_FLOW( 2, "tv_master_cntl=%x", values->tv_master_cntl ); - values->tv_uv_adr = 0xc8; + memcpy( values->tv_upsample_filter_coeff, std_upsample_filter_coeff, + RADEON_TV_UPSAMP_COEFF_NUM * sizeof( uint32 )); + + // setup output timing + memcpy( values->tv_hor_timing, hor_timings[tv_format-1], + RADEON_TV_TIMING_SIZE * sizeof( uint16 )); + memcpy( values->tv_vert_timing, vert_timings[tv_format-1], + RADEON_TV_TIMING_SIZE * sizeof( uint16 ) ); + + // arbitrary position of vertical timing table in FIFO + values->tv_uv_adr = TV_UV_ADR_INI; } -// mapping of offset in port_regs to register address -typedef struct register_mapping { - uint16 address; // register address - uint16 offset; // offset in port_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( port_regs, tv_master_cntl ) }, - { RADEON_TV_HRESTART, offsetof( port_regs, tv_hrestart ) }, - { RADEON_TV_VRESTART, offsetof( port_regs, tv_vrestart ) }, - { RADEON_TV_FRESTART, offsetof( port_regs, tv_frestart ) }, - { RADEON_TV_FTOTAL, offsetof( port_regs, tv_ftotal ) }, - { 0, 0 } -}; - -// PLL registers to program -static const register_mapping intern_reg_mapping_pll[] = { - { RADEON_TV_PLL_CNTL, offsetof( port_regs, tv_tv_pll_cntl ) }, - { RADEON_TV_PLL_CNTL1, offsetof( port_regs, tv_pll_cntl1 ) }, - { RADEON_TV_PLL_FINE_CNTL, offsetof( port_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( port_regs, tv_htotal ) }, - { RADEON_TV_HDISP, offsetof( port_regs, tv_hdisp ) }, - { RADEON_TV_HSTART, offsetof( port_regs, tv_hstart ) }, - { RADEON_TV_VTOTAL, offsetof( port_regs, tv_vtotal ) }, - { RADEON_TV_VDISP, offsetof( port_regs, tv_vdisp ) }, - { RADEON_TV_TIMING_CNTL, offsetof( port_regs, tv_timing_cntl ) }, - { RADEON_TV_VSCALER_CNTL1, offsetof( port_regs, tv_vscaler_cntl1 ) }, - { RADEON_TV_VSCALER_CNTL2, offsetof( port_regs, tv_vscaler_cntl2 ) }, - { RADEON_TV_Y_SAW_TOOTH_CNTL, offsetof( port_regs, tv_y_saw_tooth_cntl ) }, - { RADEON_TV_Y_RISE_CNTL, offsetof( port_regs, tv_y_rise_cntl ) }, - { RADEON_TV_Y_FALL_CNTL, offsetof( port_regs, tv_y_fall_cntl ) }, - { RADEON_TV_MODULATOR_CNTL1, offsetof( port_regs, tv_modulator_cntl1 ) }, - { RADEON_TV_MODULATOR_CNTL2, offsetof( port_regs, tv_modulator_cntl2 ) }, - { RADEON_TV_RGB_CNTL, offsetof( port_regs, tv_rgb_cntl ) }, - { RADEON_TV_UV_ADR, offsetof( port_regs, tv_uv_adr ) }, - { RADEON_TV_PRE_DAC_MUX_CNTL, offsetof( port_regs, tv_pre_dac_mux_cntl ) }, - { 0, 0 } -}; - -// registers to write when things settled down -static const register_mapping intern_reg_mapping_finish[] = { - { RADEON_TV_DAC_CNTL, offsetof( port_regs, tv_dac_cntl ) }, - { RADEON_TV_MASTER_CNTL, offsetof( port_regs, tv_master_cntl ) }, - { 0, 0 } -}; - - -// Rage Theatre TV-Out: - -// registers to write at first -static const register_mapping theatre_reg_mapping_start[] = { - { THEATRE_VIP_MASTER_CNTL, offsetof( port_regs, tv_master_cntl ) }, - { THEATRE_VIP_TVO_DATA_DELAY_A, offsetof( port_regs, tv_data_delay_a ) }, - { THEATRE_VIP_TVO_DATA_DELAY_B, offsetof( port_regs, tv_data_delay_b ) }, - - { THEATRE_VIP_CLKOUT_CNTL, offsetof( port_regs, tv_clkout_cntl ) }, - { THEATRE_VIP_PLL_CNTL0, offsetof( port_regs, tv_pll_cntl1 ) }, - - { THEATRE_VIP_HRESTART, offsetof( port_regs, tv_hrestart ) }, - { THEATRE_VIP_VRESTART, offsetof( port_regs, tv_vrestart ) }, - { THEATRE_VIP_FRESTART, offsetof( port_regs, tv_frestart ) }, - { THEATRE_VIP_FTOTAL, offsetof( port_regs, tv_ftotal ) }, - - { THEATRE_VIP_CLOCK_SEL_CNTL, offsetof( port_regs, tv_clock_sel_cntl ) }, - { THEATRE_VIP_TV_PLL_CNTL, offsetof( port_regs, tv_tv_pll_cntl ) }, - { THEATRE_VIP_CRT_PLL_CNTL, offsetof( port_regs, tv_crt_pll_cntl ) }, - - { THEATRE_VIP_HTOTAL, offsetof( port_regs, tv_htotal ) }, - { THEATRE_VIP_HSIZE, offsetof( port_regs, tv_hsize ) }, - { THEATRE_VIP_HDISP, offsetof( port_regs, tv_hdisp ) }, - { THEATRE_VIP_HSTART, offsetof( port_regs, tv_hstart ) }, - { THEATRE_VIP_VTOTAL, offsetof( port_regs, tv_vtotal ) }, - { THEATRE_VIP_VDISP, offsetof( port_regs, tv_vdisp ) }, - - { THEATRE_VIP_TIMING_CNTL, offsetof( port_regs, tv_timing_cntl ) }, - - { THEATRE_VIP_VSCALER_CNTL, offsetof( port_regs, tv_vscaler_cntl1 ) }, - { THEATRE_VIP_VSCALER_CNTL2, offsetof( port_regs, tv_vscaler_cntl2 ) }, - { THEATRE_VIP_SYNC_SIZE, offsetof( port_regs, tv_sync_size ) }, - { THEATRE_VIP_Y_SAW_TOOTH_CNTL, offsetof( port_regs, tv_y_saw_tooth_cntl ) }, - { THEATRE_VIP_Y_RISE_CNTL, offsetof( port_regs, tv_y_rise_cntl ) }, - { THEATRE_VIP_Y_FALL_CNTL, offsetof( port_regs, tv_y_fall_cntl ) }, - - { THEATRE_VIP_MODULATOR_CNTL1, offsetof( port_regs, tv_modulator_cntl1 ) }, - { THEATRE_VIP_MODULATOR_CNTL2, offsetof( port_regs, tv_modulator_cntl2 ) }, - - { THEATRE_VIP_RGB_CNTL, offsetof( port_regs, tv_rgb_cntl ) }, - - { THEATRE_VIP_UV_ADR, offsetof( port_regs, tv_uv_adr ) }, - - { THEATRE_VIP_PRE_DAC_MUX_CNTL, offsetof( port_regs, tv_pre_dac_mux_cntl ) }, - { THEATRE_VIP_FRAME_LOCK_CNTL, offsetof( port_regs, tv_frame_lock_cntl ) }, - { 0, 0 } -}; - -// registers to write when things settled down -static const register_mapping theatre_reg_mapping_finish[] = { - { THEATRE_VIP_TV_DAC_CNTL, offsetof( port_regs, tv_dac_cntl ) }, - { THEATRE_VIP_MASTER_CNTL, offsetof( port_regs, tv_master_cntl ) }, - { 0, 0 } -}; - - -// write list of MM I/O registers -static void writeMMIORegList( accelerator_info *ai, port_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) ); - } -} - - -// write list of PLL registers -static void writePLLRegList( accelerator_info *ai, port_regs *values, const register_mapping *mapping ) +// get address of horizontal timing table in FIFO +static uint16 getHorTimingTableAddr( + impactv_regs *values, bool internal_encoder ) { - 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) ); - } -} - - -// write list of Rage Theatre registers -static void writeTheatreRegList( accelerator_info *ai, port_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) ); - } -} - - -// program TV-Out registers -void Radeon_ProgramTVRegisters( accelerator_info *ai, port_regs *values, bool internal_encoder ) -{ - uint32 orig_tv_master_cntl = values->tv_master_cntl; - - // 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 | - (uint32)0xf0; + switch( (values->tv_uv_adr & RADEON_TV_UV_ADR_HCODE_TABLE_SEL_MASK) + >> RADEON_TV_UV_ADR_HCODE_TABLE_SEL_SHIFT ) + { + case 0: + return internal_encoder ? RADEON_TV_MAX_FIFO_ADDR_INTERN : RADEON_TV_MAX_FIFO_ADDR; - if( internal_encoder ) { - writeMMIORegList( ai, values, intern_reg_mapping_before_pll ); - writePLLRegList( ai, values, intern_reg_mapping_pll ); - writeMMIORegList( ai, values, intern_reg_mapping_after_pll ); - - snooze( 50000 ); - - values->tv_master_cntl = orig_tv_master_cntl; - writeMMIORegList( ai, values, intern_reg_mapping_finish ); - } else { - writeTheatreRegList( ai, values, theatre_reg_mapping_start ); - - snooze( 50000 ); - - values->tv_master_cntl = orig_tv_master_cntl; - writeTheatreRegList( ai, values, intern_reg_mapping_finish ); - } -} - - -// read list of MM I/O registers -static void readMMIORegList( accelerator_info *ai, port_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 ); + case 1: + return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK) + >> RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT) * 2; + case 2: + return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE3_TOP_ADR_MASK) + >> RADEON_TV_UV_ADR_TABLE3_TOP_ADR_SHIFT) * 2; -/* SHOW_FLOW( 2, "%x=%x", mapping->address, - *(uint32 *)((char *)(values) + mapping->offset) );*/ - } -} - - -// read list of PLL registers -static void readPLLRegList( accelerator_info *ai, port_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) );*/ - } -} - - -// read list of Rage Theatre registers -static void readTheatreRegList( accelerator_info *ai, port_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) ); - } -} - - -// read TV-Out registers -void Radeon_ReadTVRegisters( accelerator_info *ai, port_regs *values, bool internal_encoder ) -{ - if( internal_encoder ) { - 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 ); - } else { - readTheatreRegList( ai, values, theatre_reg_mapping_start ); - readTheatreRegList( ai, values, intern_reg_mapping_finish ); - } -} - - -// 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 + return 0; + } +} + +// get address of vertical timing table in FIFO +static uint16 getVertTimingTableAddr( + impactv_regs *values ) +{ + switch( (values->tv_uv_adr & RADEON_TV_UV_ADR_VCODE_TABLE_SEL_MASK) + >> RADEON_TV_UV_ADR_VCODE_TABLE_SEL_SHIFT ) + { + case 0: + return ((values->tv_uv_adr & RADEON_TV_UV_ADR_MAX_UV_ADR_MASK) + >> RADEON_TV_UV_ADR_MAX_UV_ADR_SHIFT) * 2 + 1; + + case 1: + return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK) + >> RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT) * 2 + 1; + + case 2: + return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE3_TOP_ADR_MASK) + >> RADEON_TV_UV_ADR_TABLE3_TOP_ADR_SHIFT) * 2 + 1; + + default: + return 0; + } +} + + +// write horizontal timing table +void Radeon_ImpacTVwriteHorTimingTable( + accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values, bool internal_encoder ) +{ + uint16 addr = getHorTimingTableAddr( values, internal_encoder ); + int i; + + for( i = 0; i < RADEON_TV_TIMING_SIZE; i += 2, --addr ) { + uint32 value = + ((uint32)values->tv_hor_timing[i] << 14) | + values->tv_hor_timing[i + 1]; + + write( ai, addr, value ); + + if( values->tv_hor_timing[i] == 0 || + values->tv_hor_timing[i + 1] == 0 ) + break; + } +} + + +// write vertical timing table +void Radeon_ImpacTVwriteVertTimingTable( + accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values ) +{ + uint16 addr = getVertTimingTableAddr( values ); + int i; + + for( i = 0; i < RADEON_TV_TIMING_SIZE; i += 2 , ++addr ) { + uint32 value = + ((uint32)values->tv_vert_timing[i + 1] << 14) | + values->tv_vert_timing[i]; + + write( ai, addr, value ); + + if( values->tv_vert_timing[i + 1] == 0 || + values->tv_vert_timing[i] == 0 ) + break; } } diff --git a/src/add-ons/accelerants/radeon/internal_tv_out.c b/src/add-ons/accelerants/radeon/internal_tv_out.c new file mode 100644 index 0000000000..4e962a3fe2 --- /dev/null +++ b/src/add-ons/accelerants/radeon/internal_tv_out.c @@ -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 + + +// 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 ); +} diff --git a/src/add-ons/accelerants/radeon/monitor_detection.c b/src/add-ons/accelerants/radeon/monitor_detection.c index 56b3e5a5dd..03e7075098 100644 --- a/src/add-ons/accelerants/radeon/monitor_detection.c +++ b/src/add-ons/accelerants/radeon/monitor_detection.c @@ -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 @@ -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 ); } diff --git a/src/add-ons/accelerants/radeon/monitor_routing.c b/src/add-ons/accelerants/radeon/monitor_routing.c index 934ffbec91..ce40b84ff3 100644 --- a/src/add-ons/accelerants/radeon/monitor_routing.c +++ b/src/add-ons/accelerants/radeon/monitor_routing.c @@ -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 ); } diff --git a/src/add-ons/accelerants/radeon/multimon.c b/src/add-ons/accelerants/radeon/multimon.c index 97c8003deb..31ef5b4a6c 100644 --- a/src/add-ons/accelerants/radeon/multimon.c +++ b/src/add-ons/accelerants/radeon/multimon.c @@ -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 ) { diff --git a/src/add-ons/accelerants/radeon/overlay.c b/src/add-ons/accelerants/radeon/overlay.c index 54c1a40004..6134671583 100644 --- a/src/add-ons/accelerants/radeon/overlay.c +++ b/src/add-ons/accelerants/radeon/overlay.c @@ -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 ); diff --git a/src/add-ons/accelerants/radeon/palette.c b/src/add-ons/accelerants/radeon/palette.c index 1a4fe3bc8a..492b016417 100644 --- a/src/add-ons/accelerants/radeon/palette.c +++ b/src/add-ons/accelerants/radeon/palette.c @@ -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 ); diff --git a/src/add-ons/accelerants/radeon/pll.c b/src/add-ons/accelerants/radeon/pll.c index 568c7a4811..4eeb767dba 100644 --- a/src/add-ons/accelerants/radeon/pll.c +++ b/src/add-ons/accelerants/radeon/pll.c @@ -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 +#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, ÷rs ); - } 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 ); } diff --git a/src/add-ons/accelerants/radeon/radeon_accelerant.h b/src/add-ons/accelerants/radeon/radeon_accelerant.h index 3b3a9818e6..b4511a36a9 100644 --- a/src/add-ons/accelerants/radeon/radeon_accelerant.h +++ b/src/add-ons/accelerants/radeon/radeon_accelerant.h @@ -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 } diff --git a/src/add-ons/accelerants/radeon/set_mode.h b/src/add-ons/accelerants/radeon/set_mode.h new file mode 100644 index 0000000000..ee742dc064 --- /dev/null +++ b/src/add-ons/accelerants/radeon/set_mode.h @@ -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 diff --git a/src/add-ons/accelerants/radeon/settings.cpp b/src/add-ons/accelerants/radeon/settings.cpp index 79ccad6d13..8c60e06ae7 100644 --- a/src/add-ons/accelerants/radeon/settings.cpp +++ b/src/add-ons/accelerants/radeon/settings.cpp @@ -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 ); } diff --git a/src/add-ons/accelerants/radeon/theatre_out.c b/src/add-ons/accelerants/radeon/theatre_out.c new file mode 100644 index 0000000000..77f23c1672 --- /dev/null +++ b/src/add-ons/accelerants/radeon/theatre_out.c @@ -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 + + +// 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 + } +} diff --git a/src/add-ons/accelerants/radeon/vesa_modes.c b/src/add-ons/accelerants/radeon/vesa_modes.c new file mode 100644 index 0000000000..c860124e52 --- /dev/null +++ b/src/add-ons/accelerants/radeon/vesa_modes.c @@ -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] ); diff --git a/src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c b/src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c index 3acc0bc210..3586f8e3b3 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c @@ -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; } diff --git a/src/add-ons/kernel/drivers/graphics/radeon/DMA.c b/src/add-ons/kernel/drivers/graphics/radeon/DMA.c index 5deea04fcd..bb045dac98 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/DMA.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/DMA.c @@ -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; diff --git a/src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c b/src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c index e79a16b09d..0e94d031ad 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c @@ -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 ); diff --git a/src/add-ons/kernel/drivers/graphics/radeon/agp.c b/src/add-ons/kernel/drivers/graphics/radeon/agp.c index 053319f92d..eda63e2903 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/agp.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/agp.c @@ -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 ); } } } diff --git a/src/add-ons/kernel/drivers/graphics/radeon/bios.c b/src/add-ons/kernel/drivers/graphics/radeon/bios.c index c252c67e26..d689dbc5b5 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/bios.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/bios.c @@ -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; diff --git a/src/add-ons/kernel/drivers/graphics/radeon/detect.c b/src/add-ons/kernel/drivers/graphics/radeon/detect.c index 4f333ef7e6..3efcf240fe 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/detect.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/detect.c @@ -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 ) diff --git a/src/add-ons/kernel/drivers/graphics/radeon/driver.c b/src/add-ons/kernel/drivers/graphics/radeon/driver.c index 58ce84be37..979caa644b 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/driver.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/driver.c @@ -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: { diff --git a/src/add-ons/kernel/drivers/graphics/radeon/init.c b/src/add-ons/kernel/drivers/graphics/radeon/init.c index 138a324d2b..4cafea26bc 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/init.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/init.c @@ -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 diff --git a/src/add-ons/kernel/drivers/graphics/radeon/irq.c b/src/add-ons/kernel/drivers/graphics/radeon/irq.c index e773433271..fb4da4ed49 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/irq.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/irq.c @@ -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; } diff --git a/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h b/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h index 7376502136..d76c9cb1b6 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h +++ b/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h @@ -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 ); diff --git a/src/add-ons/kernel/drivers/graphics/radeon/vip.c b/src/add-ons/kernel/drivers/graphics/radeon/vip.c index 32cb819ded..96ff84d977 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/vip.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/vip.c @@ -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; +}