Implement read and write operations on SC_TOP_LEFT, SC_BOTTOM_RIGHT,
and SRC_SC_BOTTOM_RIGHT registers. These registers are also updated
when the src and/or dst clipping fields on DP_GUI_MASTER_CNTL are set
to default clipping.
Scissor clipping is used when rendering text in X.org. The r128 driver
sends host data much wider than is necessary to draw a glyph and cuts it
down to size using clipping before rendering. The actual clipping
implementation follows in a future patch.
Signed-off-by: Chad Jablonski <chad@jablonski.xyz>
---
hw/display/ati.c | 26 ++++++++++++++++++++++++++
hw/display/ati_int.h | 3 +++
hw/display/ati_regs.h | 12 ++++++++++--
3 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/hw/display/ati.c b/hw/display/ati.c
index 0b4298d078..eb9b30672f 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -510,6 +510,15 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
case DEFAULT_SC_BOTTOM_RIGHT:
val = s->regs.default_sc_bottom_right;
break;
+ case SC_TOP_LEFT:
+ val = s->regs.sc_top_left;
+ break;
+ case SC_BOTTOM_RIGHT:
+ val = s->regs.sc_bottom_right;
+ break;
+ case SRC_SC_BOTTOM_RIGHT:
+ val = s->regs.src_sc_bottom_right;
+ break;
default:
break;
}
@@ -862,6 +871,14 @@ static void ati_mm_write(void *opaque, hwaddr addr,
s->regs.dp_datatype = (data & 0x0f00) >> 8 | (data & 0x30f0) << 4 |
(data & 0x4000) << 16;
s->regs.dp_mix = (data & GMC_ROP3_MASK) | (data & 0x7000000) >> 16;
+
+ if ((data & GMC_SRC_CLIPPING_MASK) == GMC_SRC_CLIP_DEFAULT) {
+ s->regs.src_sc_bottom_right = s->regs.default_sc_bottom_right;
+ }
+ if ((data & GMC_DST_CLIPPING_MASK) == GMC_DST_CLIP_DEFAULT) {
+ s->regs.sc_top_left = 0;
+ s->regs.sc_bottom_right = s->regs.default_sc_bottom_right;
+ }
break;
case DST_WIDTH_X:
s->regs.dst_x = data & 0x3fff;
@@ -937,6 +954,15 @@ static void ati_mm_write(void *opaque, hwaddr addr,
case DEFAULT_SC_BOTTOM_RIGHT:
s->regs.default_sc_bottom_right = data & 0x3fff3fff;
break;
+ case SC_TOP_LEFT:
+ s->regs.sc_top_left = data;
+ break;
+ case SC_BOTTOM_RIGHT:
+ s->regs.sc_bottom_right = data;
+ break;
+ case SRC_SC_BOTTOM_RIGHT:
+ s->regs.src_sc_bottom_right = data;
+ break;
default:
break;
}
diff --git a/hw/display/ati_int.h b/hw/display/ati_int.h
index 708cc1dd3a..aab3cbf81a 100644
--- a/hw/display/ati_int.h
+++ b/hw/display/ati_int.h
@@ -86,6 +86,9 @@ typedef struct ATIVGARegs {
uint32_t default_pitch;
uint32_t default_tile;
uint32_t default_sc_bottom_right;
+ uint32_t sc_top_left;
+ uint32_t sc_bottom_right;
+ uint32_t src_sc_bottom_right;
} ATIVGARegs;
struct ATIVGAState {
diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h
index d7127748ff..2b56b9fb66 100644
--- a/hw/display/ati_regs.h
+++ b/hw/display/ati_regs.h
@@ -392,8 +392,6 @@
/* DP_GUI_MASTER_CNTL bit constants */
#define GMC_SRC_PITCH_OFFSET_CNTL 0x00000001
#define GMC_DST_PITCH_OFFSET_CNTL 0x00000002
-#define GMC_SRC_CLIP_DEFAULT 0x00000000
-#define GMC_DST_CLIP_DEFAULT 0x00000000
#define GMC_BRUSH_SOLIDCOLOR 0x000000d0
#define GMC_SRC_DSTCOLOR 0x00003000
#define GMC_BYTE_ORDER_MSB_TO_LSB 0x00000000
@@ -404,6 +402,16 @@
#define GMC_WRITE_MASK_SET 0x40000000
#define GMC_DP_CONVERSION_TEMP_6500 0x00000000
+/* DP_GUI_MASTER_CNTL DP_SRC_CLIPPING named constants */
+#define GMC_SRC_CLIPPING_MASK 0x00000004
+#define GMC_SRC_CLIP_DEFAULT 0x00000000
+#define GMC_SRC_CLIP_LEAVE_ALONE 0x00000004
+
+/* DP_GUI_MASTER_CNTL DP_DST_CLIPPING named constants */
+#define GMC_DST_CLIPPING_MASK 0x00000008
+#define GMC_DST_CLIP_DEFAULT 0x00000000
+#define GMC_DST_CLIP_LEAVE_ALONE 0x00000008
+
/* DP_GUI_MASTER_CNTL ROP3 named constants */
#define GMC_ROP3_MASK 0x00ff0000
#define ROP3_BLACKNESS 0x00000000
--
2.51.0
On Sun, 2 Nov 2025, Chad Jablonski wrote:
> Implement read and write operations on SC_TOP_LEFT, SC_BOTTOM_RIGHT,
> and SRC_SC_BOTTOM_RIGHT registers. These registers are also updated
> when the src and/or dst clipping fields on DP_GUI_MASTER_CNTL are set
> to default clipping.
>
> Scissor clipping is used when rendering text in X.org. The r128 driver
> sends host data much wider than is necessary to draw a glyph and cuts it
> down to size using clipping before rendering. The actual clipping
> implementation follows in a future patch.
>
> Signed-off-by: Chad Jablonski <chad@jablonski.xyz>
> ---
> hw/display/ati.c | 26 ++++++++++++++++++++++++++
> hw/display/ati_int.h | 3 +++
> hw/display/ati_regs.h | 12 ++++++++++--
> 3 files changed, 39 insertions(+), 2 deletions(-)
>
> diff --git a/hw/display/ati.c b/hw/display/ati.c
> index 0b4298d078..eb9b30672f 100644
> --- a/hw/display/ati.c
> +++ b/hw/display/ati.c
> @@ -510,6 +510,15 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
> case DEFAULT_SC_BOTTOM_RIGHT:
> val = s->regs.default_sc_bottom_right;
> break;
> + case SC_TOP_LEFT:
> + val = s->regs.sc_top_left;
> + break;
> + case SC_BOTTOM_RIGHT:
> + val = s->regs.sc_bottom_right;
> + break;
> + case SRC_SC_BOTTOM_RIGHT:
> + val = s->regs.src_sc_bottom_right;
> + break;
> default:
> break;
> }
> @@ -862,6 +871,14 @@ static void ati_mm_write(void *opaque, hwaddr addr,
> s->regs.dp_datatype = (data & 0x0f00) >> 8 | (data & 0x30f0) << 4 |
> (data & 0x4000) << 16;
> s->regs.dp_mix = (data & GMC_ROP3_MASK) | (data & 0x7000000) >> 16;
> +
> + if ((data & GMC_SRC_CLIPPING_MASK) == GMC_SRC_CLIP_DEFAULT) {
> + s->regs.src_sc_bottom_right = s->regs.default_sc_bottom_right;
> + }
> + if ((data & GMC_DST_CLIPPING_MASK) == GMC_DST_CLIP_DEFAULT) {
> + s->regs.sc_top_left = 0;
> + s->regs.sc_bottom_right = s->regs.default_sc_bottom_right;
> + }
Or is this what you meant by style? Now I get that. I think the bits
should not reset the regs just cause the operation to use the default
values instead but if you can verify what actual hardware does that would
be best.
Regards,
BALATON Zoltan
> break;
> case DST_WIDTH_X:
> s->regs.dst_x = data & 0x3fff;
> @@ -937,6 +954,15 @@ static void ati_mm_write(void *opaque, hwaddr addr,
> case DEFAULT_SC_BOTTOM_RIGHT:
> s->regs.default_sc_bottom_right = data & 0x3fff3fff;
> break;
> + case SC_TOP_LEFT:
> + s->regs.sc_top_left = data;
> + break;
> + case SC_BOTTOM_RIGHT:
> + s->regs.sc_bottom_right = data;
> + break;
> + case SRC_SC_BOTTOM_RIGHT:
> + s->regs.src_sc_bottom_right = data;
> + break;
> default:
> break;
> }
> diff --git a/hw/display/ati_int.h b/hw/display/ati_int.h
> index 708cc1dd3a..aab3cbf81a 100644
> --- a/hw/display/ati_int.h
> +++ b/hw/display/ati_int.h
> @@ -86,6 +86,9 @@ typedef struct ATIVGARegs {
> uint32_t default_pitch;
> uint32_t default_tile;
> uint32_t default_sc_bottom_right;
> + uint32_t sc_top_left;
> + uint32_t sc_bottom_right;
> + uint32_t src_sc_bottom_right;
> } ATIVGARegs;
>
> struct ATIVGAState {
> diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h
> index d7127748ff..2b56b9fb66 100644
> --- a/hw/display/ati_regs.h
> +++ b/hw/display/ati_regs.h
> @@ -392,8 +392,6 @@
> /* DP_GUI_MASTER_CNTL bit constants */
> #define GMC_SRC_PITCH_OFFSET_CNTL 0x00000001
> #define GMC_DST_PITCH_OFFSET_CNTL 0x00000002
> -#define GMC_SRC_CLIP_DEFAULT 0x00000000
> -#define GMC_DST_CLIP_DEFAULT 0x00000000
> #define GMC_BRUSH_SOLIDCOLOR 0x000000d0
> #define GMC_SRC_DSTCOLOR 0x00003000
> #define GMC_BYTE_ORDER_MSB_TO_LSB 0x00000000
> @@ -404,6 +402,16 @@
> #define GMC_WRITE_MASK_SET 0x40000000
> #define GMC_DP_CONVERSION_TEMP_6500 0x00000000
>
> +/* DP_GUI_MASTER_CNTL DP_SRC_CLIPPING named constants */
> +#define GMC_SRC_CLIPPING_MASK 0x00000004
> +#define GMC_SRC_CLIP_DEFAULT 0x00000000
> +#define GMC_SRC_CLIP_LEAVE_ALONE 0x00000004
> +
> +/* DP_GUI_MASTER_CNTL DP_DST_CLIPPING named constants */
> +#define GMC_DST_CLIPPING_MASK 0x00000008
> +#define GMC_DST_CLIP_DEFAULT 0x00000000
> +#define GMC_DST_CLIP_LEAVE_ALONE 0x00000008
> +
> /* DP_GUI_MASTER_CNTL ROP3 named constants */
> #define GMC_ROP3_MASK 0x00ff0000
> #define ROP3_BLACKNESS 0x00000000
>
>> + if ((data & GMC_SRC_CLIPPING_MASK) == GMC_SRC_CLIP_DEFAULT) {
>> + s->regs.src_sc_bottom_right = s->regs.default_sc_bottom_right;
>> + }
>> + if ((data & GMC_DST_CLIPPING_MASK) == GMC_DST_CLIP_DEFAULT) {
>> + s->regs.sc_top_left = 0;
>> + s->regs.sc_bottom_right = s->regs.default_sc_bottom_right;
>> + }
>
> Or is this what you meant by style? Now I get that. I think the bits
> should not reset the regs just cause the operation to use the default
> values instead but if you can verify what actual hardware does that would
> be best.
Hi BALATON,
I've tested this on the real 'Rage 128 Pro Ultra TF' and it shows that this is
the correct behavior (copying to the registers). I was definitely a bit
surprised!
I've run this test both with X running (idle over ssh) and prior to
starting X with the same results. I would like to write a bare-metal test
to make sure that the environment is a bit more controlled. But I struggled
with modesetting and it was looking like it was going to become a bit of a
rabbit hole. So I settled on testing under Linux for now and left that for
another day.
Here is the output:
Test SRC clipping
====================================
** Initializing DEFAULT_SC_BOTTOM_RIGHT to 0x0 **
** Initializing SRC_SC_BOTTOM to 0x0 **
** Initializing SRC_SC_RIGHT to 0x0 **
Initial State
------------------------------------
DEFAULT_GUI_MASTER_CNTL: 0x4a1de00f
DEFAULT_SC_BOTTOM_RIGHT: 0x00000000
SRC_SC_BOTTOM: 0x00000000
SRC_SC_RIGHT: 0x00000000
** Setting DEFAULT_SC_BOTTOM_RIGHT to 0x0aaa0bbb **
** Setting SRC_SC_BOTTOM to 0x111 **
** Setting SRC_SC_RIGHT to 0x222 **
State After Setting
------------------------------------
DEFAULT_GUI_MASTER_CNTL: 0x4a1de00f
DEFAULT_SC_BOTTOM_RIGHT: 0x0aaa0bbb
SRC_SC_BOTTOM: 0x00000111
SRC_SC_RIGHT: 0x00000222
** Setting GMC_SRC_CLIPPING to default **
State After Setting Default
------------------------------------
DEFAULT_GUI_MASTER_CNTL: 0x4a1de00b
DEFAULT_SC_BOTTOM_RIGHT: 0x0aaa0bbb
SRC_SC_BOTTOM: 0x00000aaa <======= Set to default
SRC_SC_RIGHT: 0x00000bbb <======= Set to default
** Setting GMC_SRC_CLIPPING to leave alone **
State After Setting Leave Alone
------------------------------------
DEFAULT_GUI_MASTER_CNTL: 0x4a1de00f
DEFAULT_SC_BOTTOM_RIGHT: 0x0aaa0bbb
SRC_SC_BOTTOM: 0x00000aaa <======= STILL default
SRC_SC_RIGHT: 0x00000bbb <======= STILL default
Test DST clipping
====================================
** Initializing DEFAULT_SC_BOTTOM_RIGHT to 0x0 **
** Initializing SC_BOTTOM to 0x0 **
** Initializing SC_RIGHT to 0x0 **
** Initializing SC_TOP to 0x0 **
** Initializing SC_LEFT to 0x0 **
Initial State
------------------------------------
DEFAULT_GUI_MASTER_CNTL: 0x4a1de00f
DEFAULT_SC_BOTTOM_RIGHT: 0x00000000
SC_BOTTOM: 0x00000000
SC_RIGHT: 0x00000000
SC_TOP: 0x00000000
SC_LEFT: 0x00000000
** Setting DEFAULT_SC_BOTTOM_RIGHT to 0x0aaa0bbb **
** Setting SC_BOTTOM to 0x111 **
** Setting SC_RIGHT to 0x222 **
** SETTING SC_TOP to 0x333 **
** SETTING SC_LEFT to 0x444 **
State After Setting
------------------------------------
DEFAULT_GUI_MASTER_CNTL: 0x4a1de00f
DEFAULT_SC_BOTTOM_RIGHT: 0x0aaa0bbb
SC_BOTTOM: 0x00000111
SC_RIGHT: 0x00000222
SC_TOP: 0x00000333
SC_LEFT: 0x00000444
** Setting GMC_DST_CLIPPING to default **
State After Setting Default
------------------------------------
DEFAULT_GUI_MASTER_CNTL: 0x4a1de007
DEFAULT_SC_BOTTOM_RIGHT: 0x0aaa0bbb
SC_BOTTOM: 0x00000aaa <======= Set to default
SC_RIGHT: 0x00000bbb <======= Set to default
SC_TOP: 0x00000000 <======= Set to default
SC_LEFT: 0x00000000 <======= Set to default
** Setting GMC_DST_CLIPPING to leave alone **
State After Setting Leave Alone
------------------------------------
DEFAULT_GUI_MASTER_CNTL: 0x4a1de00f
DEFAULT_SC_BOTTOM_RIGHT: 0x0aaa0bbb
SC_BOTTOM: 0x00000aaa <======= STILL default
SC_RIGHT: 0x00000bbb <======= STILL default
SC_TOP: 0x00000000 <======= STILL default
SC_LEFT: 0x00000000 <======= STILL default
And the source:
===============================================================================
/*
* ATI Rage 128 Pro Clipping Mode Hardware Test
*
* Tests whether clipping mode bits exhibit latching or dynamic behavior
*
* Build: gcc -std=c99 -o test test.c -lpci
* Requirements: libpci-dev, root privileges, ATI Rage 128 Pro hardware
* Note: Run with X.org idle (SSH session recommended)
*/
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <pci/pci.h>
#define ATI_VENDOR_ID 0x1002
#define MAX_ATI_DEVICES 10
#define DP_GUI_MASTER_CNTL 0x146c
#define SRC_SC_BOTTOM_RIGHT 0x16f4
#define SRC_SC_BOTTOM 0x165C
#define SRC_SC_RIGHT 0x1654
#define DEFAULT_SC_BOTTOM_RIGHT 0x16e8
#define SC_TOP_LEFT 0x1640
#define SC_LEFT 0x1640
#define SC_TOP 0x1648
#define SC_BOTTOM_RIGHT 0x1644
#define SC_RIGHT 0x1644
#define SC_BOTTOM 0x164C
#define DST_OFFSET 0x1404
#define DST_PITCH 0x1408
#define DP_BRUSH_FRGD_CLR 0x147c
#define DP_WRITE_MASK 0x16cc
#define DST_HEIGHT 0x1410
#define DST_X_Y 0x1594
#define DST_WIDTH_X 0x1588
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
void run_tests(void *bar2);
struct pci_dev *find_device(struct pci_access *pacc,
char *name_out, int name_len);
void print_devices(struct pci_access *pacc);
void *map_bar(struct pci_dev *dev, int bar_idx);
static inline uint32_t reg_read(void *base, uint32_t offset);
static inline uint32_t reg_write(void *base, uint32_t offset, uint32_t value);
int main(int argc, char **argv) {
struct pci_access *pacc = pci_alloc();
char name[256];
struct pci_dev *dev = find_device(pacc, name, sizeof(name));
void *bar2 = map_bar(dev, 2);
run_tests(bar2);
return 0;
}
void test_dst_clipping(void *bar2) {
uint32_t dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
uint32_t default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
uint32_t sc_bottom = reg_read(bar2, SC_BOTTOM);
uint32_t sc_right = reg_read(bar2, SC_RIGHT);
uint32_t sc_top = reg_read(bar2, SC_TOP);
uint32_t sc_left = reg_read(bar2, SC_LEFT);
printf("Test DST clipping\n");
printf("====================================\n\n");
printf("** Initializing DEFAULT_SC_BOTTOM_RIGHT to 0x0 **\n");
printf("** Initializing SC_BOTTOM to 0x0 **\n");
printf("** Initializing SC_RIGHT to 0x0 **\n");
printf("** Initializing SC_TOP to 0x0 **\n");
printf("** Initializing SC_LEFT to 0x0 **\n");
reg_write(bar2, DEFAULT_SC_BOTTOM_RIGHT, 0x0);
reg_write(bar2, SC_BOTTOM, 0x0);
reg_write(bar2, SC_RIGHT, 0x0);
reg_write(bar2, SC_TOP, 0x0);
reg_write(bar2, SC_LEFT, 0x0);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
sc_bottom = reg_read(bar2, SC_BOTTOM);
sc_right = reg_read(bar2, SC_RIGHT);
sc_top = reg_read(bar2, SC_TOP);
sc_left = reg_read(bar2, SC_LEFT);
printf("\n");
printf("Initial State\n");
printf("------------------------------------\n");
printf("DEFAULT_GUI_MASTER_CNTL: 0x%08x\n", dp_gui_master_cntl);
printf("DEFAULT_SC_BOTTOM_RIGHT: 0x%08x\n", default_sc_bottom_right);
printf("SC_BOTTOM: 0x%08x\n", sc_bottom);
printf("SC_RIGHT: 0x%08x\n", sc_right);
printf("SC_TOP: 0x%08x\n", sc_top);
printf("SC_LEFT: 0x%08x\n", sc_left);
printf("\n");
printf("** Setting DEFAULT_SC_BOTTOM_RIGHT to 0x0aaa0bbb **\n");
printf("** Setting SC_BOTTOM to 0x111 **\n");
printf("** Setting SC_RIGHT to 0x222 **\n");
printf("** SETTING SC_TOP to 0x333 **\n");
printf("** SETTING SC_LEFT to 0x444 **\n");
reg_write(bar2, DEFAULT_SC_BOTTOM_RIGHT, 0x0aaa0bbb);
reg_write(bar2, SC_BOTTOM, 0x00000111);
reg_write(bar2, SC_RIGHT, 0x00000222);
reg_write(bar2, SC_TOP, 0x00000333);
reg_write(bar2, SC_LEFT, 0x00000444);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
sc_bottom = reg_read(bar2, SC_BOTTOM);
sc_right = reg_read(bar2, SC_RIGHT);
sc_top = reg_read(bar2, SC_TOP);
sc_left = reg_read(bar2, SC_LEFT);
printf("\n");
printf("State After Setting\n");
printf("------------------------------------\n");
printf("DEFAULT_GUI_MASTER_CNTL: 0x%08x\n", dp_gui_master_cntl);
printf("DEFAULT_SC_BOTTOM_RIGHT: 0x%08x\n", default_sc_bottom_right);
printf("SC_BOTTOM: 0x%08x\n", sc_bottom);
printf("SC_RIGHT: 0x%08x\n", sc_right);
printf("SC_TOP: 0x%08x\n", sc_top);
printf("SC_LEFT: 0x%08x\n", sc_left);
printf("\n");
printf("** Setting GMC_DST_CLIPPING to default **\n");
reg_write(bar2, DP_GUI_MASTER_CNTL, dp_gui_master_cntl & ~0x8);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
sc_bottom = reg_read(bar2, SC_BOTTOM);
sc_right = reg_read(bar2, SC_RIGHT);
sc_top = reg_read(bar2, SC_TOP);
sc_left = reg_read(bar2, SC_LEFT);
printf("\n");
printf("State After Setting Default\n");
printf("------------------------------------\n");
printf("DEFAULT_GUI_MASTER_CNTL: 0x%08x\n", dp_gui_master_cntl);
printf("DEFAULT_SC_BOTTOM_RIGHT: 0x%08x\n", default_sc_bottom_right);
printf("SC_BOTTOM: 0x%08x\n", sc_bottom);
printf("SC_RIGHT: 0x%08x\n", sc_right);
printf("SC_TOP: 0x%08x\n", sc_top);
printf("SC_LEFT: 0x%08x\n", sc_left);
printf("\n");
printf("** Setting GMC_DST_CLIPPING to leave alone **\n");
reg_write(bar2, DP_GUI_MASTER_CNTL, dp_gui_master_cntl | 0x8);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
sc_bottom = reg_read(bar2, SC_BOTTOM);
sc_right = reg_read(bar2, SC_RIGHT);
sc_top = reg_read(bar2, SC_TOP);
sc_left = reg_read(bar2, SC_LEFT);
printf("\n");
printf("State After Setting Leave Alone\n");
printf("------------------------------------\n");
printf("DEFAULT_GUI_MASTER_CNTL: 0x%08x\n", dp_gui_master_cntl);
printf("DEFAULT_SC_BOTTOM_RIGHT: 0x%08x\n", default_sc_bottom_right);
printf("SC_BOTTOM: 0x%08x\n", sc_bottom);
printf("SC_RIGHT: 0x%08x\n", sc_right);
printf("SC_TOP: 0x%08x\n", sc_top);
printf("SC_LEFT: 0x%08x\n", sc_left);
printf("\n");
}
void test_src_clipping(void *bar2) {
uint32_t dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
uint32_t default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
uint32_t src_sc_bottom = reg_read(bar2, SRC_SC_BOTTOM);
uint32_t src_sc_right = reg_read(bar2, SRC_SC_RIGHT);
printf("Test SRC clipping\n");
printf("====================================\n\n");
printf("** Initializing DEFAULT_SC_BOTTOM_RIGHT to 0x0 **\n");
printf("** Initializing SRC_SC_BOTTOM to 0x0 **\n");
printf("** Initializing SRC_SC_RIGHT to 0x0 **\n");
reg_write(bar2, DEFAULT_SC_BOTTOM_RIGHT, 0x0);
reg_write(bar2, SRC_SC_BOTTOM, 0x0);
reg_write(bar2, SRC_SC_RIGHT, 0x0);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
src_sc_bottom = reg_read(bar2, SRC_SC_BOTTOM);
src_sc_right = reg_read(bar2, SRC_SC_RIGHT);
printf("\n");
printf("Initial State\n");
printf("------------------------------------\n");
printf("DEFAULT_GUI_MASTER_CNTL: 0x%08x\n", dp_gui_master_cntl);
printf("DEFAULT_SC_BOTTOM_RIGHT: 0x%08x\n", default_sc_bottom_right);
printf("SRC_SC_BOTTOM: 0x%08x\n", src_sc_bottom);
printf("SRC_SC_RIGHT: 0x%08x\n", src_sc_right);
printf("\n");
printf("** Setting DEFAULT_SC_BOTTOM_RIGHT to 0x0aaa0bbb **\n");
printf("** Setting SRC_SC_BOTTOM to 0x111 **\n");
printf("** Setting SRC_SC_RIGHT to 0x222 **\n");
reg_write(bar2, DEFAULT_SC_BOTTOM_RIGHT, 0x0aaa0bbb);
reg_write(bar2, SRC_SC_BOTTOM, 0x00000111);
reg_write(bar2, SRC_SC_RIGHT, 0x00000222);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
src_sc_bottom = reg_read(bar2, SRC_SC_BOTTOM);
src_sc_right = reg_read(bar2, SRC_SC_RIGHT);
printf("\n");
printf("State After Setting\n");
printf("------------------------------------\n");
printf("DEFAULT_GUI_MASTER_CNTL: 0x%08x\n", dp_gui_master_cntl);
printf("DEFAULT_SC_BOTTOM_RIGHT: 0x%08x\n", default_sc_bottom_right);
printf("SRC_SC_BOTTOM: 0x%08x\n", src_sc_bottom);
printf("SRC_SC_RIGHT: 0x%08x\n", src_sc_right);
printf("\n");
printf("** Setting GMC_SRC_CLIPPING to default **\n");
reg_write(bar2, DP_GUI_MASTER_CNTL, dp_gui_master_cntl & ~0x4);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
src_sc_bottom = reg_read(bar2, SRC_SC_BOTTOM);
src_sc_right = reg_read(bar2, SRC_SC_RIGHT);
printf("\n");
printf("State After Setting Default\n");
printf("------------------------------------\n");
printf("DEFAULT_GUI_MASTER_CNTL: 0x%08x\n", dp_gui_master_cntl);
printf("DEFAULT_SC_BOTTOM_RIGHT: 0x%08x\n", default_sc_bottom_right);
printf("SRC_SC_BOTTOM: 0x%08x\n", src_sc_bottom);
printf("SRC_SC_RIGHT: 0x%08x\n", src_sc_right);
printf("\n");
printf("** Setting GMC_SRC_CLIPPING to leave alone **\n");
reg_write(bar2, DP_GUI_MASTER_CNTL, dp_gui_master_cntl | 0x4);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
dp_gui_master_cntl = reg_read(bar2, DP_GUI_MASTER_CNTL);
default_sc_bottom_right = reg_read(bar2, DEFAULT_SC_BOTTOM_RIGHT);
src_sc_bottom = reg_read(bar2, SRC_SC_BOTTOM);
src_sc_right = reg_read(bar2, SRC_SC_RIGHT);
printf("\n");
printf("State After Setting Leave Alone\n");
printf("------------------------------------\n");
printf("DEFAULT_GUI_MASTER_CNTL: 0x%08x\n", dp_gui_master_cntl);
printf("DEFAULT_SC_BOTTOM_RIGHT: 0x%08x\n", default_sc_bottom_right);
printf("SRC_SC_BOTTOM: 0x%08x\n", src_sc_bottom);
printf("SRC_SC_RIGHT: 0x%08x\n", src_sc_right);
printf("\n");
}
void run_tests(void *bar2) {
test_src_clipping(bar2);
test_dst_clipping(bar2);
}
struct pci_dev *find_device(struct pci_access *pacc,
char *name_out, int name_len) {
struct pci_dev *dev, *it;
int device_count = 0;
pci_init(pacc);
pci_scan_bus(pacc);
for (it = pacc->devices; it; it = it->next) {
if (it->vendor_id == ATI_VENDOR_ID) {
if (device_count == 0) {
dev = it;
}
device_count += 1;
}
}
if (device_count == 0) {
printf("No ATI devices found\n");
exit(1);
}
if (device_count > 1) {
printf("Found multiple ATI devices:\n");
print_devices(pacc);
}
pci_lookup_name(pacc, name_out, name_len,
PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
dev->vendor_id, dev->device_id);
printf("# %s\n\n", name_out);
return dev;
}
void print_devices(struct pci_access *pacc) {
struct pci_dev *dev;
char name[256];
for (dev = pacc->devices; dev; dev = dev->next) {
if (dev->vendor_id != ATI_VENDOR_ID) continue;
pci_lookup_name(pacc, name, sizeof(name),
PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
dev->vendor_id, dev->device_id);
printf("\t- %s\n", name);
}
}
void *map_bar(struct pci_dev *dev, int bar_idx) {
char pci_loc[32];
sprintf(pci_loc, "%04x:%02x:%02x.%d", dev->domain, dev->bus,
dev->dev, dev->func);
char base_path[256];
sprintf(base_path, "/sys/bus/pci/devices/%s", pci_loc);
char bar_path[256];
sprintf(bar_path, "%s/resource%d", base_path, bar_idx);
int bar_fd = open(bar_path, O_RDWR | O_SYNC);
if (bar_fd == -1) FATAL;
void *bar = mmap(NULL, dev->size[bar_idx], PROT_READ | PROT_WRITE,
MAP_SHARED, bar_fd, 0);
if (bar == (void *) -1) FATAL;
return bar;
}
static inline uint32_t reg_read(void *base, uint32_t offset) {
volatile uint32_t *reg = (volatile uint32_t *)(base + offset);
return *reg;
}
static inline uint32_t reg_write(void *base, uint32_t offset, uint32_t value) {
volatile uint32_t *reg = (volatile uint32_t *)(base + offset);
*reg = value;
}
===============================================================================
I haven't tested them yet, but I'll also run this test for
GMC_SRC_PITCH_OFFSET_CNTL and GMC_DST_PITCH_OFFSET_CNTL to confirm that
they have the same behavior.
© 2016 - 2026 Red Hat, Inc.