summaryrefslogtreecommitdiff
path: root/src/cim/cim_gp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cim/cim_gp.c')
-rw-r--r--src/cim/cim_gp.c3392
1 files changed, 3392 insertions, 0 deletions
diff --git a/src/cim/cim_gp.c b/src/cim/cim_gp.c
new file mode 100644
index 0000000..fc105c9
--- /dev/null
+++ b/src/cim/cim_gp.c
@@ -0,0 +1,3392 @@
+/*
+ * Copyright (c) 2006 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ */
+
+ /*
+ * Cimarron graphics processor routines. These routines program the graphics
+ * hardware using the graphics command buffer.
+ */
+
+/*---------------------*/
+/* CIMARRON GP GLOBALS */
+/*---------------------*/
+
+CIMARRON_STATIC unsigned long gp3_bpp = 0;
+CIMARRON_STATIC unsigned long gp3_ch3_bpp = 0;
+CIMARRON_STATIC unsigned long gp3_pat_origin = 0;
+CIMARRON_STATIC unsigned long gp3_buffer_lead = 0;
+CIMARRON_STATIC unsigned long gp3_cmd_header;
+CIMARRON_STATIC unsigned long gp3_cmd_top;
+CIMARRON_STATIC unsigned long gp3_cmd_bottom;
+CIMARRON_STATIC unsigned long gp3_cmd_current;
+CIMARRON_STATIC unsigned long gp3_cmd_next;
+CIMARRON_STATIC unsigned long gp3_blt_mode;
+CIMARRON_STATIC unsigned long gp3_vec_mode;
+CIMARRON_STATIC unsigned long gp3_raster_mode;
+CIMARRON_STATIC unsigned long gp3_pix_shift;
+CIMARRON_STATIC unsigned long gp3_ch3_pat;
+CIMARRON_STATIC unsigned long gp3_blt;
+CIMARRON_STATIC unsigned long gp3_blt_flags;
+CIMARRON_STATIC unsigned long gp3_src_stride;
+CIMARRON_STATIC unsigned long gp3_dst_stride;
+CIMARRON_STATIC unsigned long gp3_src_format;
+CIMARRON_STATIC unsigned long gp3_src_pix_shift;
+CIMARRON_STATIC unsigned long gp3_pat_format;
+CIMARRON_STATIC unsigned long gp3_pat_pix_shift;
+CIMARRON_STATIC unsigned long gp3_fb_base;
+CIMARRON_STATIC unsigned long gp3_vector_pattern_color;
+CIMARRON_STATIC unsigned long gp3_scratch_base;
+CIMARRON_STATIC unsigned long gp3_base_register;
+CIMARRON_STATIC unsigned long gp3_vec_pat;
+
+/*---------------------------------------------------------------------------
+ * gp_set_limit_on_buffer_lead
+ *
+ * This routine is used to specify the maximum number of bytes in the command
+ * buffer by which software can lead the graphics processor. When declaring
+ * a BLT with the CIMGP_BLTFLAGS_LIMITBUFFER flag set, Cimarron will wait
+ * until the command buffer read and write pointers differ by no more than
+ * 'lead' bytes. This can be useful to limit the time lag possible when
+ * creating a command buffer full of simple BLT commands.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_limit_on_buffer_lead(unsigned long lead)
+{
+ gp3_buffer_lead = lead;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_command_buffer_base
+ *
+ * This routine is used to program the command buffer region in physical
+ * memory. The command buffer start address must be 1MB aligned. start and
+ * stop refer to endpoints within the associated 16MB region. Command buffers
+ * larger than 16MB are not supported.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_command_buffer_base(unsigned long address, unsigned long start,
+ unsigned long stop)
+{
+ Q_WORD msr_value;
+
+ /* WAIT FOR IDLE */
+ /* Obviously, we cannot change the command buffer pointer while the GP */
+ /* is currently fetching commands. */
+
+ gp_wait_until_idle();
+
+ /* WRITE THE COMMAND BUFFER BASE */
+
+ msr_read64(MSR_DEVICE_GEODELX_GP, MSR_GEODELINK_CONFIG, &msr_value);
+ msr_value.low &= 0xF000FFFF;
+ msr_value.low |= (address >> 4) & 0x0FFF0000;
+ msr_write64(MSR_DEVICE_GEODELX_GP, MSR_GEODELINK_CONFIG, &msr_value);
+
+ /* WRITE THE BASE OFFSETS */
+ /* We also reset the write and read pointers. The hardware will */
+ /* automatically update the write pointer when the read pointer */
+ /* is updated to prevent the hardware from getting confused when */
+ /* initializing a new command buffer. */
+
+ WRITE_GP32(GP3_CMD_TOP, start);
+ WRITE_GP32(GP3_CMD_BOT, stop);
+ WRITE_GP32(GP3_CMD_READ, start);
+
+ /* SAVE THE BASE ADDRESSES */
+ /* These are used to determine the appropriate wrap point. */
+
+ gp3_cmd_current = gp3_cmd_top = start;
+ gp3_cmd_bottom = stop;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_frame_buffer_base
+ *
+ * This routine is used to program the base address of the frame buffer in
+ * physical memory. The frame buffer address must be 16MB aligned. Cimarron
+ * tracks the base address because the maximum frame buffer size may exceed
+ * 16MB. Any primitive will thus program the corresponding 16MB region into
+ * all base offset registers as well as program the offset into the 16MB
+ * region. The size parameter is provided to allow Cimarron to claim the
+ * last 1MB of space to be used as a scratch area for workarounds or
+ * expanded functionality.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_frame_buffer_base(unsigned long address, unsigned long size)
+{
+ gp3_scratch_base = size - GP3_SCRATCH_BUFFER_SIZE;
+ gp3_fb_base = address >> 24;
+ gp3_base_register =
+ (gp3_fb_base << 24) | (gp3_fb_base << 14) | (gp3_fb_base << 4);
+ WRITE_GP32(GP3_BASE_OFFSET, gp3_base_register);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_bpp
+ *
+ * This routine sets the output BPP of the GP. The BPP used by the GP does
+ * not have to match the display BPP, but that is usually the case. The
+ * supported BPP values are as follows:
+ *
+ * 8 - palettized 8BPP
+ * 12 - 4:4:4:4
+ * 15 - 1:5:5:5
+ * 16 - 0:5:6:5
+ * 32 - 8:8:8:8
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_bpp(int bpp)
+{
+ /* STORE BPP */
+ /* The bpp is not updated until the next call to gp_set_raster_mode. */
+ /* This allows the gp_set_bpp call to happen outside of a BLT. It */
+ /* also implies that no registers need be written in this routine. */
+
+ switch (bpp) {
+ case 8:
+ gp3_bpp = GP3_RM_BPPFMT_332;
+ gp3_ch3_bpp = GP3_CH3_SRC_3_3_2;
+ gp3_pix_shift = 0;
+ break;
+ case 12:
+ gp3_bpp = GP3_RM_BPPFMT_4444;
+ gp3_ch3_bpp = GP3_CH3_SRC_4_4_4_4;
+ gp3_pix_shift = 1;
+ break;
+ case 15:
+ gp3_bpp = GP3_RM_BPPFMT_1555;
+ gp3_ch3_bpp = GP3_CH3_SRC_1_5_5_5;
+ gp3_pix_shift = 1;
+ break;
+ case 16:
+ gp3_bpp = GP3_RM_BPPFMT_565;
+ gp3_ch3_bpp = GP3_CH3_SRC_0_5_6_5;
+ gp3_pix_shift = 1;
+ break;
+ case 24:
+ case 32:
+ gp3_bpp = GP3_RM_BPPFMT_8888;
+ gp3_ch3_bpp = GP3_CH3_SRC_8_8_8_8;
+ gp3_pix_shift = 2;
+ break;
+ default:
+ gp3_bpp = GP3_RM_BPPFMT_332;
+ gp3_ch3_bpp = GP3_CH3_SRC_3_3_2;
+ gp3_pix_shift = 0;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_declare_blt
+ *
+ * This routine is used to prepare for a 2D BLT. Its primary function
+ * is to verify that enough room is available in the command buffer
+ * to hold a BLT command. This command can be called multiple times if
+ * necessary. For example, if a function calls this routine on entry, but
+ * later realizes that a LUT load command must be executed before the BLT,
+ * the application could call gp_set_color_pattern and then call
+ * gp_declare_blt to declare the BLT. This is possible because the hardware
+ * buffer pointer is not updated until a new BLT is actually executed. An
+ * application must take care not to call any routines that perform a buffer
+ * command, (such as gp_set_color_pattern) between gp_declare_blt and the
+ * routines used to program the BLT parameters. In addition to checking for
+ * available space, this routine also performs the following actions:
+ * - Sets the wrap bit if this BLT will pass close to the end of the
+ * buffer.
+ * - Writes the command header.
+ *
+ * The available flags are defined as follows:
+ * 0x01 - Preserve the LUT
+ * 0x02 - Preserve the color pattern.
+ * 0x04 - Enable prefetch.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_declare_blt(unsigned long flags)
+{
+ unsigned long temp;
+
+ gp3_blt = 1;
+ gp3_blt_flags = flags;
+
+ /* SET ADDRESS OF NEXT COMMAND */
+ /* A summary of the command buffer logic is as follows: */
+ /* - If after a basic BLT we will not have room for the largest */
+ /* command (a full line of host source data), we set the wrap */
+ /* bit. This will waste up to a whopping 8K of command buffer */
+ /* space, but it simplifies the logic for all commands. */
+ /* - If we are wrapping, we have extra logic to ensure that we */
+ /* don't skip over the current GP read pointer. */
+
+ gp3_cmd_next = gp3_cmd_current + GP3_BLT_COMMAND_SIZE;
+
+ /* CHECK WRAP CONDITION */
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+ gp3_cmd_header = GP3_BLT_HDR_TYPE | GP3_BLT_HDR_WRAP;
+
+ /* WAIT FOR HARDWARE */
+ /* When wrapping, we must take steps to ensure that we do not */
+ /* wrap over the current hardware read pointer. We do this by */
+ /* verifying that the hardware is not between us and the end of */
+ /* the command buffer. We also have a special case to make sure */
+ /* that the hardware is not currently reading the top of the */
+ /* command buffer. */
+
+ GP3_WAIT_WRAP(temp);
+ } else {
+ gp3_cmd_header = GP3_BLT_HDR_TYPE;
+
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ }
+
+ if (flags & CIMGP_BLTFLAGS_LIMITBUFFER) {
+ while (1) {
+ temp = READ_GP32(GP3_CMD_READ);
+ if (((gp3_cmd_current >= temp)
+ && ((gp3_cmd_current - temp) <= gp3_buffer_lead))
+ || ((gp3_cmd_current < temp)
+ && ((gp3_cmd_current + (gp3_cmd_bottom - temp)) <=
+ gp3_buffer_lead))) {
+ break;
+ }
+ }
+ }
+
+ /* SET THE CURRENT BUFFER POINTER */
+ /* We initialize a pointer to the current buffer base to avoid an */
+ /* extra addition for every buffer write. */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* SET THE HAZARD BIT */
+
+ if (flags & CIMGP_BLTFLAGS_HAZARD)
+ gp3_cmd_header |= GP3_BLT_HDR_HAZARD_ENABLE;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_declare_vector
+ *
+ * This routine is used to prepare for a 2D vector. It has no other function
+ * except to verify that enough room is available in the command buffer
+ * to hold a vector command. The same rules that apply to BLTs apply to
+ * vectors. (See the documentation for gp_declare_blt).
+ *-------------------------------------------------------------------------*/
+
+void
+gp_declare_vector(unsigned long flags)
+{
+ unsigned long temp;
+
+ gp3_blt = 0;
+ gp3_blt_flags = flags;
+
+ /* SET ADDRESS OF NEXT COMMAND */
+ /* The logic to force a wrap during a vector is identical */
+ /* to the BLT logic. */
+
+ /* ALLOCATE SPACE FOR AN ADDITIONAL VECTOR TO CLEAR THE BYTE ENABLES */
+
+ gp3_cmd_next = gp3_cmd_current + GP3_VECTOR_COMMAND_SIZE +
+ GP3_VECTOR_COMMAND_SIZE + 32;
+
+ /* CHECK WRAP CONDITION */
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+ gp3_cmd_header = GP3_VEC_HDR_TYPE | GP3_VEC_HDR_WRAP;
+
+ /* CHECK WRAP CONDITION */
+
+ GP3_WAIT_WRAP(temp);
+ } else {
+ gp3_cmd_header = GP3_VEC_HDR_TYPE;
+
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+
+ gp3_cmd_next -= GP3_VECTOR_COMMAND_SIZE + 32;
+ }
+
+ if (flags & CIMGP_BLTFLAGS_LIMITBUFFER) {
+ while (1) {
+ temp = READ_GP32(GP3_CMD_READ);
+ if (((gp3_cmd_current >= temp)
+ && ((gp3_cmd_current - temp) <= gp3_buffer_lead))
+ || ((gp3_cmd_current < temp)
+ && ((gp3_cmd_current + (gp3_cmd_bottom - temp)) <=
+ gp3_buffer_lead))) {
+ break;
+ }
+ }
+ }
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* SET THE HAZARD BIT */
+
+ if (flags & CIMGP_BLTFLAGS_HAZARD)
+ gp3_cmd_header |= GP3_VEC_HDR_HAZARD_ENABLE;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_write_parameters
+ *
+ * This routine is called to write all recent parameters to the hardware.
+ * This routine is necessary for any implementation that performs the setup
+ * for a BLT separate from the actual BLT. An example would be a driver
+ * that prepares for multiple pattern fills by programming the ROP,
+ * pattern color and destination stride. The driver might then perform
+ * repeated pattern fills with minimal effort.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_write_parameters(void)
+{
+ /* WRITE THE COMMAND HEADER */
+ /* Command header is at offset 0 for BLTs and vectors */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+
+ /* INCREMENT THE CURRENT WRITE POINTER */
+
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* UPDATE THE GP WRITE POINTER */
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_current);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_raster_operation
+ *
+ * This is generally the first routine called when programming a BLT. This
+ * routine performs the following functions:
+ * - Sets the initial value of the GP3_RASTER_MODE register in the buffer.
+ * - Clears any 8x8 pattern if the ROP does not involve pattern data.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_raster_operation(unsigned char ROP)
+{
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE;
+
+ /* WRITE THE RASTER MODE REGISTER */
+ /* This register is in the same location in BLT and vector commands */
+
+ gp3_raster_mode = gp3_bpp | (unsigned long)ROP;
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE, gp3_raster_mode);
+
+ /* CHECK IF DESTINATION IS REQUIRED */
+
+ if ((ROP & 0x55) ^ ((ROP >> 1) & 0x55)) {
+ gp3_blt_mode = GP3_BM_DST_REQ;
+ gp3_vec_mode = GP3_VM_DST_REQ;
+ } else {
+ gp3_blt_mode = gp3_vec_mode = 0;
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * gp_set_alpha_operation
+ *
+ * BLTs are generally one of two types, a ROPed BLT or a BLT composited using
+ * alpha blending. For the latter, this routine is used to configure the
+ * mathematical function used to create the blended output. This routine
+ * should generally be called first when programming a BLT. The available
+ * parameters mirror the hardware and are described as follows:
+ *
+ * alpha_operation =
+ * 0 - alpha * A
+ * 1 - (1 - alpha) * B
+ * 2 - A + (1 - alpha)*B
+ * 3 - alpha*A + (1 - alpha)*B
+ *
+ * alpha_type =
+ * 0 - alpha component of channel A
+ * 1 - alpha component of channel B
+ * 2 - Constant alpha
+ * 3 - Constant 1
+ * 4 - The color components of channel A
+ * 5 - The color components of channel B
+ * 6 - Alpha comes from the alpha channel of the source before the source
+ * undergoes color conversion.
+ *
+ * channel =
+ * 0 - Channel A = source, channel B = destination
+ * 1 - Channel B = source, channel A = destination
+ *
+ * apply_alpha =
+ * 1 - Apply alpha blend to only the RGB portion of the pixel. This must be
+ * set when the source or destination format do not include an alpha
+ * channel.
+ * 2 - Apply alpha blend only to the alpha portion of the pixel. This
+ * implies that both destination and source include an alpha channel.
+ * 3 - Apply alpha blend to both the RGB and alpha portions of the pixel.
+ *
+ * Alpha-blended vectors are not currently supported.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_alpha_operation(int alpha_operation, int alpha_type, int channel,
+ int apply_alpha, unsigned char alpha)
+{
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE;
+
+ /* THE AVAILABLE ALPHA DEFINITIONS FOLLOW THE HARDWARE */
+ /* This allows us to avoid giant switch structures, but it */
+ /* also implies that there is no mechanism to detect invalid */
+ /* parameters. */
+
+ gp3_raster_mode = gp3_bpp | (unsigned long)alpha |
+ ((unsigned long)apply_alpha << 22) |
+ ((unsigned long)alpha_operation << 20) |
+ ((unsigned long)alpha_type << 17) | ((unsigned long)channel << 16);
+
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE, gp3_raster_mode);
+
+ /* CHECK IF DESTINATION IS REQUIRED */
+
+ if ((alpha_operation == CIMGP_ALPHA_TIMES_A &&
+ channel == CIMGP_CHANNEL_A_SOURCE &&
+ alpha_type != CIMGP_CHANNEL_B_ALPHA &&
+ alpha_type != CIMGP_ALPHA_FROM_RGB_B) ||
+ (alpha_operation == CIMGP_BETA_TIMES_B &&
+ channel == CIMGP_CHANNEL_A_DEST &&
+ alpha_type != CIMGP_CHANNEL_A_ALPHA &&
+ alpha_type != CIMGP_ALPHA_FROM_RGB_A)) {
+ gp3_blt_mode = 0;
+ } else
+ gp3_blt_mode = GP3_BM_DST_REQ;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_solid_pattern
+ *
+ * This routine is called to program the hardware for a solid pattern. It
+ * need not be called for any other reason. As a side effect, this routine
+ * will clear any 8x8 pattern data.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_solid_pattern(unsigned long color)
+{
+ /* CHANNEL 3 IS NOT NEEDED FOR SOLID PATTERNS */
+
+ gp3_ch3_pat = 0;
+
+ /* SET SOLID PATTERN IN COMMAND BUFFER */
+ /* We are assuming that only one pattern type is ever set for a */
+ /* BLT. We are also assuming that gp_set_raster_operation will */
+ /* be called before this routine. With these assumptions, we */
+ /* will thus never have to change the raster mode register for */
+ /* solid patterns. */
+
+ if (gp3_blt) {
+ gp3_cmd_header |= GP3_BLT_HDR_PAT_CLR0_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_PAT_COLOR_0, color);
+ } else {
+ gp3_cmd_header |= GP3_VEC_HDR_PAT_CLR0_ENABLE;
+
+ WRITE_COMMAND32(GP3_VECTOR_PAT_COLOR_0, color);
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_mono_pattern
+ *
+ * This routine is called to program the hardware for a monochrome pattern.
+ * As a side effect, this routine will clear any 8x8 pattern data.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_mono_pattern(unsigned long bgcolor, unsigned long fgcolor,
+ unsigned long data0, unsigned long data1, int transparent, int x, int y)
+{
+ /* CHANNEL 3 IS NOT NEEDED FOR MONOCHROME PATTERNS */
+
+ gp3_ch3_pat = 0;
+
+ /* UPDATE RASTER MODE REGISTER */
+
+ if (transparent)
+ gp3_raster_mode |= GP3_RM_PAT_MONO | GP3_RM_PAT_TRANS;
+ else
+ gp3_raster_mode |= GP3_RM_PAT_MONO;
+
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE, gp3_raster_mode);
+
+ /* SET MONOCHROME PATTERN DATA AND COLORS */
+
+ if (gp3_blt) {
+ gp3_cmd_header |=
+ (GP3_BLT_HDR_PAT_CLR0_ENABLE | GP3_BLT_HDR_PAT_CLR1_ENABLE |
+ GP3_BLT_HDR_PAT_DATA0_ENABLE | GP3_BLT_HDR_PAT_DATA1_ENABLE);
+
+ WRITE_COMMAND32(GP3_BLT_PAT_COLOR_0, bgcolor);
+ WRITE_COMMAND32(GP3_BLT_PAT_COLOR_1, fgcolor);
+ WRITE_COMMAND32(GP3_BLT_PAT_DATA_0, data0);
+ WRITE_COMMAND32(GP3_BLT_PAT_DATA_1, data1);
+ } else {
+ gp3_cmd_header |=
+ (GP3_VEC_HDR_PAT_CLR0_ENABLE | GP3_VEC_HDR_PAT_CLR1_ENABLE |
+ GP3_VEC_HDR_PAT_DATA0_ENABLE | GP3_VEC_HDR_PAT_DATA1_ENABLE);
+
+ WRITE_COMMAND32(GP3_VECTOR_PAT_COLOR_0, bgcolor);
+ WRITE_COMMAND32(GP3_VECTOR_PAT_COLOR_1, fgcolor);
+ WRITE_COMMAND32(GP3_VECTOR_PAT_DATA_0, data0);
+ WRITE_COMMAND32(GP3_VECTOR_PAT_DATA_1, data1);
+ }
+
+ /* SAVE PATTERN ORIGIN */
+
+ gp3_pat_origin = ((unsigned long)y << 29) |
+ (((unsigned long)x & 7) << 26);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_pattern_origin
+ *
+ * This routine overrides the pattern origins set in gp_set_mono_pattern or
+ * gp_set_color_pattern. It is generally used to override the original
+ * pattern origin due to a change in clipping.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_pattern_origin(int x, int y)
+{
+ /* SAVE PATTERN ORIGIN */
+
+ gp3_pat_origin = ((unsigned long)y << 29) |
+ (((unsigned long)x & 7) << 26);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_color_pattern
+ *
+ * This routine is called to program a 8x8 color pattern into the LUT
+ * hardware. Unlike the other pattern routines, this routine must be called
+ * before any gp_declare_xxxx routines. The pattern that is programmed into
+ * the hardware will stay persistent for all subsequent primitives until one
+ * of the following conditions happens.
+ * - Another pattern type is programmed.
+ * - A color-conversion BLT rotation BLT.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_color_pattern(unsigned long *pattern, int format, int x, int y)
+{
+ unsigned long size_dwords, temp;
+
+ gp3_ch3_pat = 1;
+
+ /* SAVE COLOR PATTERN SOURCE INFO
+ * Color patterns can be in a format different than the primary display.
+ * 4BPP patterns are not supported.
+ */
+
+ gp3_pat_pix_shift = (unsigned long)((format >> 2) & 3);
+ gp3_pat_format = (((unsigned long)format & 0xF) << 24) |
+ (((unsigned long)format & 0x10) << 17) |
+ GP3_CH3_COLOR_PAT_ENABLE | GP3_CH3_C3EN;
+
+ size_dwords = (64 << gp3_pat_pix_shift) >> 2;
+
+ /* CHECK FOR WRAP AFTER LUT LOAD */
+ /* Primitive size is 12 plus the amount of data. */
+
+ gp3_cmd_next = gp3_cmd_current + (size_dwords << 2) + 12;
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+ gp3_cmd_header = GP3_LUT_HDR_TYPE | GP3_LUT_HDR_WRAP |
+ GP3_LUT_HDR_DATA_ENABLE;
+
+ /* WAIT FOR HARDWARE */
+ /* Same logic as BLT wrapping. */
+
+ GP3_WAIT_WRAP(temp);
+ } else {
+ gp3_cmd_header = GP3_LUT_HDR_TYPE | GP3_LUT_HDR_DATA_ENABLE;
+
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ }
+
+ /* SAVE CURRENT BUFFER POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* PREPARE FOR COMMAND BUFFER DATA WRITES */
+ /* Pattern data is contiguous DWORDs at LUT address 0x100 */
+
+ WRITE_COMMAND32(0, gp3_cmd_header);
+ WRITE_COMMAND32(4, 0x100);
+ WRITE_COMMAND32(8, size_dwords | GP3_LUT_DATA_TYPE);
+
+ /* WRITE ALL DATA */
+
+ WRITE_COMMAND_STRING32(12, pattern, 0, size_dwords);
+
+ /* START OPERATION */
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* SAVE PATTERN ORIGIN */
+
+ gp3_pat_origin = ((unsigned long)y << 29) |
+ (((unsigned long)x & 7) << 26);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_mono_source
+ *
+ * This routine is called to program the colors for monochrome source data.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_mono_source(unsigned long bgcolor, unsigned long fgcolor,
+ int transparent)
+{
+ /* UPDATE RASTER MODE REGISTER IF TRANSPARENT */
+
+ if (transparent) {
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE;
+ gp3_raster_mode |= GP3_RM_SRC_TRANS;
+
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE, gp3_raster_mode);
+ }
+
+ /* SET MONOCHROME SOURCE COLORS */
+ /* Note that this routine only sets the colors. The actual */
+ /* source type is determined by the final output routine */
+ /* (gp_mono_bitmap_xxx, gp_color_bitmap_xxx, etc.) */
+
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_FG_ENABLE | GP3_BLT_HDR_SRC_BG_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_SRC_COLOR_FG, fgcolor);
+ WRITE_COMMAND32(GP3_BLT_SRC_COLOR_BG, bgcolor);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_solid_source
+ *
+ * This routine is called to program a solid source color. A solid source
+ * color is used primarily for vectors or antialiased text.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_solid_source(unsigned long color)
+{
+ /* SET SOLID SOURCE COLOR */
+ /* The solid source register is in the same place for both BLTs and */
+ /* vectors. */
+
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_FG_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_SRC_COLOR_FG, color);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_source_transparency
+ *
+ * This routine sets the source transparency and mask to be used in future
+ * rendering operations. Transparency is cleared by gp_set_raster_operation,
+ * so this routine should never be called first.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_source_transparency(unsigned long color, unsigned long mask)
+{
+ gp3_raster_mode |= GP3_RM_SRC_TRANS;
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE | GP3_BLT_HDR_SRC_FG_ENABLE |
+ GP3_BLT_HDR_SRC_BG_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE, gp3_raster_mode);
+ WRITE_COMMAND32(GP3_BLT_SRC_COLOR_FG, color);
+ WRITE_COMMAND32(GP3_BLT_SRC_COLOR_BG, mask);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_program_lut
+ *
+ * This routine is called to program the hardware LUT with color-conversion
+ * information. This routine should be called before any gp_declare_xxxx
+ * routines.
+ *
+ * colors - Pointer to an array of DWORDs for color expansion.
+ *
+ * full_lut - Selector between 4BPP and 8BPP expansion. The hardware is
+ * initialized with 16 dwords for 4BPP expansion and 256 dwords
+ * for 8BPP expansion.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_program_lut(unsigned long *colors, int full_lut)
+{
+ unsigned long size_dwords, temp;
+
+ /* SIZE IS EITHER 16 DWORDS (4BPP) or 256 DWORDS (8BPP) */
+
+ if (full_lut)
+ size_dwords = 256;
+ else
+ size_dwords = 16;
+
+ /* CHECK FOR WRAP AFTER LUT LOAD */
+ /* Primitive size is 12 plus the amount of data. */
+
+ gp3_cmd_next = gp3_cmd_current + (size_dwords << 2) + 12;
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+ gp3_cmd_header = GP3_LUT_HDR_TYPE | GP3_LUT_HDR_WRAP |
+ GP3_LUT_HDR_DATA_ENABLE;
+
+ /* WAIT FOR HARDWARE */
+ /* Same logic as BLT wrapping. */
+
+ GP3_WAIT_WRAP(temp);
+ } else {
+ gp3_cmd_header = GP3_LUT_HDR_TYPE | GP3_LUT_HDR_DATA_ENABLE;
+
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ }
+
+ /* SAVE CURRENT BUFFER POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* PREPARE FOR COMMAND BUFFER DATA WRITES */
+ /* Pattern data is contiguous DWORDs at LUT address 0 */
+
+ WRITE_COMMAND32(0, gp3_cmd_header);
+ WRITE_COMMAND32(4, 0);
+ WRITE_COMMAND32(8, (size_dwords | GP3_LUT_DATA_TYPE));
+
+ /* WRITE ALL DATA */
+
+ WRITE_COMMAND_STRING32(12, colors, 0, size_dwords);
+
+ /* START OPERATION */
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_vector_pattern
+ *
+ * This routine is called to program the hardware LUT with a vector pattern.
+ * A vector pattern is programmed as a 32-bit mask that specifies a
+ * transparency pattern. A length parameter is used to specify patterns
+ * smaller than 32. Note that vectors in Geode LX do not continue across
+ * corners. The beginning of each vector will always begin with bit 0 of the
+ * vector pattern. It is the responsibility of the caller to update the
+ * pattern if an alternate behavior is desired.
+ *
+ * This routine faces the same restrictions of all routines that program
+ * the LUT, in that it must be called before any gp_declare_xxxx routines,
+ * it cannot be combined with an 8x8 color pattern, color conversion or
+ * rotation.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_vector_pattern(unsigned long pattern, unsigned long color, int length)
+{
+ unsigned long temp, mask;
+
+ gp3_ch3_pat = 1;
+ gp3_vector_pattern_color = color;
+
+ /* CREATE SUITABLE PATTERN MASK */
+ /* The GP requires a minimum of four pixels in a vector pattern. We */
+ /* can get around this restriction by doubling any patterns smaller */
+ /* than 4 pixels. */
+
+ while (length < 4) {
+ mask = 0xFFFFFFFF >> (32 - length);
+ pattern = (pattern << length) | (pattern & mask);
+ length <<= 1;
+ }
+ mask = 0xFFFFFFFF >> (32 - length);
+
+ gp3_vec_pat = pattern;
+
+ /* CHECK FOR WRAP AFTER LUT LOAD */
+
+ gp3_cmd_next = gp3_cmd_current + GP3_VECTOR_PATTERN_COMMAND_SIZE;
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+ gp3_cmd_header = GP3_LUT_HDR_TYPE | GP3_LUT_HDR_WRAP |
+ GP3_LUT_HDR_DATA_ENABLE;
+
+ /* WAIT FOR HARDWARE */
+ /* Same logic as BLT wrapping. */
+
+ GP3_WAIT_WRAP(temp);
+ } else {
+ gp3_cmd_header = GP3_LUT_HDR_TYPE | GP3_LUT_HDR_DATA_ENABLE;
+
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ }
+
+ /* SAVE CURRENT BUFFER POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* PREPARE FOR COMMAND BUFFER DATA WRITES */
+ /* Pattern data is 2 DWORDs at 0x100 and 0x101 */
+
+ WRITE_COMMAND32(0, gp3_cmd_header);
+ WRITE_COMMAND32(4, 0x100);
+ WRITE_COMMAND32(8, (2 | GP3_LUT_DATA_TYPE));
+ WRITE_COMMAND32(12, pattern);
+ WRITE_COMMAND32(16, mask);
+
+ /* START OPERATION */
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_strides
+ *
+ * This routine is called to program the pitch between successive lines of
+ * data in the frame buffer. The strides should be DWORD aligned and less
+ * than 64K. These restrictions are not checked by the API.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_strides(unsigned long dst_stride, unsigned long src_stride)
+{
+ /* SAVE STRIDES */
+ /* The source stride may be needed later for channel 3 source data and */
+ /* we may need to use these strides in calculations. */
+
+ gp3_src_stride = src_stride;
+ gp3_dst_stride = dst_stride;
+
+ /* ENABLE STRIDES */
+ /* The stride register is in the same place for BLTs and vectors */
+
+ gp3_cmd_header |= GP3_BLT_HDR_STRIDE_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_STRIDE, ((src_stride << 16) | dst_stride));
+}
+
+/*---------------------------------------------------------------------------
+ * gp_set_source_format
+ *
+ * This routine is used to program the format of source data used in
+ * subsequent color-conversion or rotation operations. Note that 4BPP
+ * indexed and 8BPP indexed source formats cannot be used when rotating, as
+ * the LUT will be destroyed. These formats also cannot be combined with an
+ * 8x8 color pattern. The supported formats mirror the hardware and are
+ * described as follows:
+ *
+ * 0 - 8BPP 3:3:2
+ * 1 - 8BPP indexed
+ * 4 - 16BPP 4:4:4:4
+ * 5 - 16BPP 1:5:5:5
+ * 6 - 16BPP 5:6:5
+ * 7 - 16BPP YUV
+ * 8 - 32BPP 8:8:8:8
+ * 13 - 4BPP indexed
+ * 20 - 16BPP 4:4:4:4 BGR
+ * 21 - 16BPP 1:5:5:5 BGR
+ * 22 - 16BPP 0:5:6:5 BGR
+ * 24 - 32BPP 8:8:8:8 BGR
+ *-------------------------------------------------------------------------*/
+
+void
+gp_set_source_format(int format)
+{
+ /* SAVE FORMAT */
+ /* We will combine the source format later when doing color conversion. */
+ /* We also save the pixel size for host source calculations. */
+ /* Conveniently, the source formats are organized such that the upper */
+ /* two bits of the nibble represent the pixel shift, with a pixel shift */
+ /* of 3 being a special case for 4BPP data. Clever, yes? Even more */
+ /* clever, bit 4 indicates BGR ordering. */
+
+ gp3_src_pix_shift = (unsigned long)((format >> 2) & 3);
+ gp3_src_format = (((unsigned long)format & 0xF) << 24) |
+ (((unsigned long)format & 0x10) << 18);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_pattern_fill
+ *
+ * This routine is called to perform a simple pattern fill. The pattern
+ * can be solid, monochrome or a preprogrammed 8x8 color pattern. If
+ * the ROP involves source data, that source data will be constant.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_pattern_fill(unsigned long dstoffset, unsigned long width,
+ unsigned long height)
+{
+ unsigned long base_register;
+
+ base_register = (gp3_base_register & ~GP3_BASE_OFFSET_DSTMASK) |
+ ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000));
+
+ /* ENABLE RELEVANT REGISTERS */
+ /* Note that we always enable and write the channel 3 mode, if only */
+ /* to turn it off. Cimarron also always writes the base offset */
+ /* register to allow operation with frame buffers larger than 16MB. */
+
+ gp3_cmd_header |= GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ /* WRITE THE REGISTERS COMMON TO ALL PATTERN TYPES */
+ /* The destination base is the frame buffer base plus whatever */
+ /* 4MB segment we happen to be BLTing to. */
+
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, ((width << 16) | height));
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base_register);
+
+ /* CHECK 8X8 COLOR PATTERN CASE */
+
+ if (gp3_ch3_pat) {
+ /* SET CHANNEL 3 PATTERN ORIGINS */
+
+ gp3_cmd_header |= GP3_BLT_HDR_CH3_OFF_ENABLE;
+
+ /* INITIALIZE CHANNEL 3 PARAMETERS */
+
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, ((width << 16) | height));
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, dstoffset & 0x3FFFFF);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, gp3_pat_format);
+ } else {
+ /* DISABLE CHANNEL 3 AND USE NORMAL PATTERN ORIGINS */
+
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, 0);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET,
+ ((dstoffset & 0x3FFFFF) | gp3_pat_origin));
+ }
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_BLT_MODE, gp3_blt_mode);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_screen_to_screen_blt
+ *
+ * This routine is called to perform a BLT from one location inside video
+ * memory to another location inside video memory. The source and destination
+ * formats are assumed to be the current BPP. Whenever possible, this routine
+ * tries to use channel 3 to fetch source data. The BLT flags can affect this
+ * behavior in the following ways:
+ * CIMGP_BLTFLAGS_PRES_COLOR_PAT
+ * A color pattern is being stored in the channel 3 buffer. It is either
+ * being stored for a later BLT or being combined with the current source
+ * data. Channel 3 cannot be used to fetch source data or the pattern
+ * will be overwritten.
+ * CIMGP_BLTFLAGS_PRES_LUT
+ * If the first flag is not set, this flag will limit the use of the
+ * channel 3 buffer to 1K.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_screen_to_screen_blt(unsigned long dstoffset, unsigned long srcoffset,
+ unsigned long width, unsigned long height, int flags)
+{
+ unsigned long base;
+ unsigned long ch3_flags = 0;
+ unsigned long blt_mode = gp3_blt_mode;
+ unsigned long size = ((width << 16) | height);
+ unsigned long dstbase, srcbase;
+
+ /* CALCULATE BASE OFFSETS */
+ /* We need to set the 4MB aligned base offsets before we add offsets */
+ /* for negative BLTs. */
+
+ srcbase = srcoffset & 0xFFC00000;
+ dstbase = dstoffset & 0xFFC00000;
+ srcoffset &= 0x3FFFFF;
+ dstoffset &= 0x3FFFFF;
+
+ /* ADJUST OFFSETS BASED ON FLAGS */
+ /* We adjust the source and destination offsets to point to the first */
+ /* byte of the first pixel of the BLT. This routine assumes that the */
+ /* source and destination regions do not wrap past the end of a 16MB */
+ /* region. */
+
+ if (flags & CIMGP_NEGXDIR) {
+ srcoffset += (width << gp3_pix_shift) - 1;
+ dstoffset += (width << gp3_pix_shift) - 1;
+ blt_mode |= GP3_BM_NEG_XDIR;
+ ch3_flags |= GP3_CH3_NEG_XDIR;
+ }
+ if (flags & CIMGP_NEGYDIR) {
+ srcoffset += (height - 1) * gp3_src_stride;
+ dstoffset += (height - 1) * gp3_dst_stride;
+ blt_mode |= GP3_BM_NEG_YDIR;
+ ch3_flags |= GP3_CH3_NEG_YDIR;
+ }
+
+ /* BRANCH BASED ON CHANNEL 3 */
+ /* If a color pattern is not being saved or used, channel 3 will */
+ /* be used to fetch source for maximum throughput. Channel 3 */
+ /* is not used if transparency or alpha blending is enabled. */
+
+ if (!(gp3_blt_flags & CIMGP_BLTFLAGS_PRES_COLOR_PAT) &&
+ !(gp3_raster_mode & GP3_RM_SRC_TRANS) && !(flags & CIMGP_NEGYDIR)) {
+ base = ((gp3_fb_base << 24) + dstbase) |
+ ((gp3_fb_base << 4) + (srcbase >> 20)) |
+ (gp3_base_register & GP3_BASE_OFFSET_SRCMASK);
+
+ gp3_cmd_header |= GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, (dstoffset | gp3_pat_origin));
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, srcoffset);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, size);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR,
+ GP3_CH3_C3EN | GP3_CH3_REPLACE_SOURCE |
+ gp3_ch3_bpp | gp3_src_stride | ch3_flags |
+ ((gp3_blt_flags & CIMGP_ENABLE_PREFETCH) << 17) |
+ ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20));
+ } else {
+ /* CALCULATE BASE OFFSET REGISTER */
+
+ base = ((gp3_fb_base << 24) + dstbase) |
+ ((gp3_fb_base << 14) + (srcbase >> 10)) |
+ (gp3_base_register & GP3_BASE_OFFSET_CH3MASK);
+
+ /* PROGRAM THE NORMAL SOURCE CHANNEL REGISTERS */
+ /* We assume that a color pattern is being ROPed with source */
+ /* data if the pattern type is color and the preserve pattern */
+ /* was set. */
+
+ blt_mode |= GP3_BM_SRC_FB;
+
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_OFF_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ if (gp3_ch3_pat) {
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, dstoffset);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, gp3_pat_format | ch3_flags);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, size);
+ } else {
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, dstoffset | gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, 0);
+ }
+
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET, srcoffset);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+ }
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_BLT_MODE, blt_mode);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_screen_to_screen_convert
+ *
+ * This routine is called to color-convert a rectangular region of the frame
+ * buffer into the current BPP. The format of the source region is programmed
+ * by gp_set_source_format.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_screen_to_screen_convert(unsigned long dstoffset, unsigned long srcoffset,
+ unsigned long width, unsigned long height, int nibble)
+{
+ unsigned long size = ((width << 16) | height);
+ unsigned long ch3_offset = srcoffset & 0x3FFFFF;
+ unsigned long ch3_size, base;
+
+ base = ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)) |
+ ((gp3_fb_base << 4) + ((srcoffset & 0xFFC00000) >> 20)) |
+ (gp3_base_register & GP3_BASE_OFFSET_SRCMASK);
+
+ /* SET NIBBLE FOR 4BPP */
+ /* 4BPP is a special case in that it requires subpixel addressing. The */
+ /* user must supply this information via the nibble parameter. This */
+ /* parameter is ignored for every other source format. */
+
+ ch3_size = size;
+ if (gp3_src_pix_shift == 3)
+ ch3_offset |= ((nibble & 1) << 25);
+ else if ((gp3_src_format & GP3_CH3_SRC_MASK) == GP3_CH3_SRC_24BPP_PACKED)
+ ch3_size = ((((width * 3) + 3) >> 2) << 16) | height;
+
+ /* SET APPROPRIATE ENABLES */
+
+ gp3_cmd_header |= GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ /* WRITE ALL BLT REGISTERS */
+
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET,
+ (dstoffset & 0x3FFFFF) | gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, ch3_size);
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, ch3_offset);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR,
+ GP3_CH3_C3EN | GP3_CH3_REPLACE_SOURCE | gp3_src_format |
+ ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20) |
+ ((gp3_blt_flags & CIMGP_ENABLE_PREFETCH) << 17) | gp3_src_stride);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_BLT_MODE, gp3_blt_mode);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_color_bitmap_to_screen_blt
+ *
+ * This routine is called to BLT data from system memory into the frame
+ * buffer. 'srcy' is deliberately omitted to prevent extra calculations for
+ * simple applications that have no source indexes.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_color_bitmap_to_screen_blt(unsigned long dstoffset, unsigned long srcx,
+ unsigned long width, unsigned long height, unsigned char *data,
+ long pitch)
+{
+ unsigned long indent, temp;
+ unsigned long total_dwords, size_dwords;
+ unsigned long dword_count, byte_count;
+ unsigned long size = ((width << 16) | height);
+ unsigned long srcoffset;
+
+ /* ASSUME BITMAPS ARE DWORD ALIGNED */
+ /* We will offset into the source data in DWORD increments. We */
+ /* set the source index to the remaining byte offset and */
+ /* increment the size of each line to account for the dont-care */
+ /* pixel(s). */
+
+ indent = srcx << gp3_pix_shift;
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+
+ /* PROGRAM THE NORMAL SOURCE CHANNEL REGISTERS */
+ /* We assume that a color pattern is being ROPed with source */
+ /* data if the pattern type is color and the preserve pattern */
+ /* was set. */
+
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_OFF_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ if (gp3_ch3_pat) {
+ gp3_cmd_header |= GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, (dstoffset & 0x3FFFFF));
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, gp3_pat_format);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, size);
+ } else {
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET,
+ ((dstoffset & 0x3FFFFF) | gp3_pat_origin));
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, 0);
+ }
+
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET, indent);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET,
+ ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)));
+ WRITE_COMMAND32(GP3_BLT_MODE, gp3_blt_mode | GP3_BM_SRC_HOST);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* CALCULATE THE SIZE OF ONE LINE */
+
+ size = (width << gp3_pix_shift) + indent;
+ total_dwords = (size + 3) >> 2;
+ size_dwords = (total_dwords << 2) + 8;
+ dword_count = (size >> 2);
+ byte_count = (size & 3);
+
+ /* CHECK FOR SMALL BLT CASE */
+
+ if (((total_dwords << 2) * height) <= GP3_BLT_1PASS_SIZE &&
+ (gp3_cmd_bottom - gp3_cmd_current) > (GP3_BLT_1PASS_SIZE + 72)) {
+ /* UPDATE THE COMMAND POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + ((total_dwords << 2) * height) + 8;
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_HOST_SOURCE_TYPE | (total_dwords * height));
+
+ while (height--) {
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ srcoffset += pitch;
+ cim_cmd_ptr += total_dwords << 2;
+ }
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ } else {
+ /*
+ * Each line will be created as a separate command buffer entry to
+ * allow line-by-line wrapping and to allow simultaneous rendering
+ * by the HW.
+ */
+
+ while (height--) {
+ /* UPDATE THE COMMAND POINTER
+ * The WRITE_COMMANDXX macros use a pointer to the current buffer
+ * space. This is created by adding gp3_cmd_current to the base
+ * pointer.
+ */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + size_dwords;
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ /* WAIT FOR HARDWARE */
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0, GP3_DATA_LOAD_HDR_TYPE |
+ GP3_DATA_LOAD_HDR_WRAP | GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0, GP3_DATA_LOAD_HDR_TYPE |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_HOST_SOURCE_TYPE | total_dwords);
+
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ /* UPDATE POINTERS */
+
+ srcoffset += pitch;
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_color_convert_blt
+ *
+ * This routine is called to convert data that is stored in system memory
+ * into the current graphics BPP. The source format is programmed in
+ * gp_set_source_format.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_color_convert_blt(unsigned long dstoffset, unsigned long srcx,
+ unsigned long width, unsigned long height,
+ unsigned char *data, long pitch)
+{
+ unsigned long indent, temp;
+ unsigned long total_dwords, size_dwords;
+ unsigned long dword_count, byte_count;
+ unsigned long size = ((width << 16) | height);
+ unsigned long ch3_size;
+ unsigned long ch3_offset, srcoffset;
+ unsigned long base;
+
+ /* ASSUME BITMAPS ARE DWORD ALIGNED */
+ /* We will offset into the source data in DWORD increments. We */
+ /* set the source index to the remaining byte offset and */
+ /* increment the size of each line to account for the dont-care */
+ /* pixel(s). For 4BPP source data, we also set the appropriate */
+ /* nibble index. */
+
+ /* CALCULATE THE SIZE OF ONE LINE */
+
+ if ((gp3_src_format & GP3_CH3_SRC_MASK) == GP3_CH3_SRC_24BPP_PACKED) {
+ /* HANDLE 24BPP
+ * Note that we do not do anything to guarantee that the source data
+ * is DWORD aligned. The logic here is that the source data will be
+ * cacheable, in which case Geode LX will not lose any clocks for
+ * unaligned moves. Also note that the channel 3 width is
+ * programmed as the number of dwords, while the normal width is
+ * programmed as the number of pixels.
+ */
+
+ srcoffset = srcx * 3;
+ ch3_offset = 0;
+ temp = width * 3;
+ ch3_size = (((temp + 3) >> 2) << 16) | height;
+ } else {
+ ch3_size = size;
+
+ if (gp3_src_pix_shift == 3) {
+ /* CALCULATE INDENT AND SOURCE OFFSET */
+
+ indent = (srcx >> 1);
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+ ch3_offset = indent | ((srcx & 1) << 25);
+
+ temp = ((width + (srcx & 1) + 1) >> 1) + indent;
+ } else {
+ indent = (srcx << gp3_src_pix_shift);
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+ ch3_offset = indent;
+
+ temp = (width << gp3_src_pix_shift) + indent;
+ }
+ }
+
+ total_dwords = (temp + 3) >> 2;
+ size_dwords = (total_dwords << 2) + 8;
+ dword_count = (temp >> 2);
+ byte_count = (temp & 3);
+
+ base = ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)) |
+ (gp3_base_register & ~GP3_BASE_OFFSET_DSTMASK);
+
+ /* SET APPROPRIATE ENABLES */
+
+ gp3_cmd_header |= GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET,
+ (dstoffset & 0x3FFFFF) | gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, ch3_offset);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, ch3_size);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, GP3_CH3_C3EN |
+ GP3_CH3_REPLACE_SOURCE | GP3_CH3_HST_SRC_ENABLE |
+ gp3_src_format | ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20));
+ WRITE_COMMAND32(GP3_BLT_MODE, gp3_blt_mode);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ if (((total_dwords << 2) * height) <= GP3_BLT_1PASS_SIZE &&
+ (gp3_cmd_bottom - gp3_cmd_current) > (GP3_BLT_1PASS_SIZE + 72)) {
+ /* UPDATE THE COMMAND POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + ((total_dwords << 2) * height) + 8;
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0, GP3_DATA_LOAD_HDR_TYPE |
+ GP3_DATA_LOAD_HDR_WRAP | GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_CH3_HOST_SOURCE_TYPE |
+ (total_dwords * height));
+
+ while (height--) {
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ srcoffset += pitch;
+ cim_cmd_ptr += total_dwords << 2;
+ }
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ } else {
+ /* WRITE DATA LINE BY LINE
+ * Each line will be created as a separate command buffer entry to
+ * allow line-by-line wrapping and to allow simultaneous rendering
+ * by the HW.
+ */
+
+ while (height--) {
+ /* UPDATE THE COMMAND POINTER
+ * The WRITE_COMMANDXX macros use a pointer to the current buffer
+ * space. This is created by adding gp3_cmd_current to the base
+ * pointer.
+ */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + size_dwords;
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ /* WAIT FOR HARDWARE */
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0, GP3_DATA_LOAD_HDR_TYPE |
+ GP3_DATA_LOAD_HDR_WRAP | GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0, GP3_DATA_LOAD_HDR_TYPE |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_CH3_HOST_SOURCE_TYPE | total_dwords);
+
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ /* UPDATE POINTERS */
+
+ srcoffset += pitch;
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_custom_convert_blt
+ *
+ * This routine is identical to gp_color_convert_blt, except that the macro
+ * to write data to the frame buffer has been replaced with a new macro. This
+ * allows a user to implement custom behavior when sending data, such as
+ * manually converting 24BPP to 32BPP, converting 2BPP to 4BPP or
+ * premultiplying alpha data.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_custom_convert_blt(unsigned long dstoffset, unsigned long srcx,
+ unsigned long width, unsigned long height,
+ unsigned char *data, long pitch)
+{
+ unsigned long indent, temp;
+ unsigned long total_dwords, size_dwords;
+ unsigned long dword_count, byte_count;
+ unsigned long size = ((width << 16) | height);
+ unsigned long ch3_offset, srcoffset;
+ unsigned long ch3_size, base;
+
+ /* ASSUME BITMAPS ARE DWORD ALIGNED */
+ /* We will offset into the source data in DWORD increments. We */
+ /* set the source index to the remaining byte offset and */
+ /* increment the size of each line to account for the dont-care */
+ /* pixel(s). For 4BPP source data, we also set the appropriate */
+ /* nibble index. */
+
+ /* CALCULATE THE SIZE OF ONE LINE */
+
+ if ((gp3_src_format & GP3_CH3_SRC_MASK) == GP3_CH3_SRC_24BPP_PACKED) {
+ /* HANDLE 24BPP
+ * Note that we do not do anything to guarantee that the source data
+ * is DWORD aligned. The logic here is that the source data will be
+ * cacheable, in which case Geode LX will not lose any clocks for
+ * unaligned moves. Also note that the channel 3 width is programmed
+ * as the number of dwords, while the normal width is programmed as
+ * the number of pixels.
+ */
+
+ srcoffset = srcx * 3;
+ ch3_offset = 0;
+ temp = width * 3;
+ ch3_size = (((temp + 3) >> 2) << 16) | height;
+ } else {
+ ch3_size = size;
+
+ if (gp3_src_pix_shift == 3) {
+ /* CALCULATE INDENT AND SOURCE OFFSET */
+
+ indent = (srcx >> 1);
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+ ch3_offset = indent | ((srcx & 1) << 25);
+
+ temp = ((width + (srcx & 1) + 1) >> 1) + indent;
+ } else {
+ indent = (srcx << gp3_src_pix_shift);
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+ ch3_offset = indent;
+
+ temp = (width << gp3_src_pix_shift) + indent;
+ }
+ }
+
+ total_dwords = (temp + 3) >> 2;
+ size_dwords = (total_dwords << 2) + 8;
+ dword_count = (temp >> 2);
+ byte_count = (temp & 3);
+
+ base = ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)) |
+ (gp3_base_register & ~GP3_BASE_OFFSET_DSTMASK);
+
+ /* SET APPROPRIATE ENABLES */
+
+ gp3_cmd_header |= GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET,
+ (dstoffset & 0x3FFFFF) | gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, ch3_offset);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, ch3_size);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, GP3_CH3_C3EN |
+ GP3_CH3_REPLACE_SOURCE | GP3_CH3_HST_SRC_ENABLE |
+ gp3_src_format | ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20));
+ WRITE_COMMAND32(GP3_BLT_MODE, gp3_blt_mode);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ if (((total_dwords << 2) * height) <= GP3_BLT_1PASS_SIZE &&
+ (gp3_cmd_bottom - gp3_cmd_current) > (GP3_BLT_1PASS_SIZE + 72)) {
+ /* UPDATE THE COMMAND POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + ((total_dwords << 2) * height) + 8;
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4,
+ GP3_CH3_HOST_SOURCE_TYPE | (total_dwords * height));
+
+ while (height--) {
+ /* WRITE DATA */
+
+ WRITE_CUSTOM_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_CUSTOM_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ srcoffset += pitch;
+ cim_cmd_ptr += total_dwords << 2;
+ }
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ } else {
+ /* WRITE DATA LINE BY LINE
+ * Each line will be created as a separate command buffer entry to
+ * allow line-by-line wrapping and to allow simultaneous rendering
+ * by the HW.
+ */
+
+ while (height--) {
+ /* UPDATE THE COMMAND POINTER
+ * The WRITE_COMMANDXX macros use a pointer to the current buffer
+ * space. This is created by adding gp3_cmd_current to the base
+ * pointer.
+ */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + size_dwords;
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ /* WAIT FOR HARDWARE */
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_CH3_HOST_SOURCE_TYPE | total_dwords);
+
+ /* WRITE DATA */
+
+ WRITE_CUSTOM_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_CUSTOM_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ /* UPDATE POINTERS */
+
+ srcoffset += pitch;
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_rotate_blt
+ *
+ * This routine is called to rotate a rectangular area of video memory. The
+ * data may be color converted during the rotation. 'Degrees' must be a
+ * multiple of 90 and indicates a clockwise rotation. Width and height
+ * refer to the width and the height of the source. The output
+ * destinations will be equal to the rotated dimensions.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_rotate_blt(unsigned long dstoffset, unsigned long srcoffset,
+ unsigned long width, unsigned long height, int degrees)
+{
+ unsigned long sizein, sizeout;
+ unsigned long ch3_flags;
+ unsigned long base;
+
+ base = ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)) |
+ ((gp3_fb_base << 4) + ((srcoffset & 0xFFC00000) >> 20)) |
+ (gp3_base_register & GP3_BASE_OFFSET_SRCMASK);
+
+ srcoffset &= 0x3FFFFF;
+ dstoffset &= 0x3FFFFF;
+
+ /* SET ROTATION PARAMETERS */
+
+ switch (degrees) {
+ case 90:
+ srcoffset += (height - 1) * gp3_src_stride;
+ sizein = ((width << 16) | height);
+ sizeout = ((height << 16) | width);
+ ch3_flags = GP3_CH3_C3EN | GP3_CH3_REPLACE_SOURCE |
+ GP3_CH3_ROTATE_ENABLE | GP3_CH3_NEG_YDIR;
+ break;
+
+ case 180:
+ srcoffset += (height - 1) * gp3_src_stride;
+ srcoffset += (width << gp3_src_pix_shift) - 1;
+ sizein = sizeout = ((width << 16) | height);
+ ch3_flags = GP3_CH3_C3EN | GP3_CH3_REPLACE_SOURCE |
+ GP3_CH3_NEG_YDIR | GP3_CH3_NEG_XDIR;
+ break;
+
+ case 270:
+ srcoffset += (width << gp3_src_pix_shift) - 1;
+ sizein = ((width << 16) | height);
+ sizeout = ((height << 16) | width);
+ ch3_flags = GP3_CH3_C3EN | GP3_CH3_REPLACE_SOURCE |
+ GP3_CH3_ROTATE_ENABLE | GP3_CH3_NEG_XDIR;
+ break;
+
+ default:
+ sizein = sizeout = ((width << 16) | height);
+ ch3_flags = GP3_CH3_C3EN | GP3_CH3_REPLACE_SOURCE;
+ break;
+ }
+
+ /* SET APPROPRIATE ENABLES */
+ /* We override the raster mode setting with a source */
+ /* copy ROP. */
+
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ /* WRITE ALL BLT REGISTERS */
+
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE, gp3_bpp | 0xCC);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, dstoffset);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, sizeout);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, sizein);
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, srcoffset);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, ch3_flags | gp3_src_format |
+ ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20) |
+ ((gp3_blt_flags & CIMGP_ENABLE_PREFETCH) << 17) | gp3_src_stride);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_BLT_MODE, gp3_blt_mode);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_mono_bitmap_to_screen_blt
+ *
+ * This routine expands and BLTs a monchrome bitmap that is stored in system
+ * memory into the framebuffer. 'data' points to an array of monochrome data.
+ * 'stride' indicates the pitch between successive lines of monochrome data.
+ * 'srcx' indicates the x coordinate within each line of blend data
+ * corresponding to the first pixel. A y coordinate for the source is
+ * deliberately omitted to avoid extra calculation for simple cases that have
+ * no y index. The calling program must adjust the data pointer accordingly.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_mono_bitmap_to_screen_blt(unsigned long dstoffset, unsigned long srcx,
+ unsigned long width, unsigned long height,
+ unsigned char *data, long stride)
+{
+ unsigned long indent, temp;
+ unsigned long total_dwords, size_dwords;
+ unsigned long dword_count, byte_count;
+ unsigned long size = ((width << 16) | height);
+ unsigned long srcoffset, src_value;
+
+ /* ASSUME BITMAPS ARE DWORD ALIGNED */
+ /* We will offset into the source data in DWORD increments. We */
+ /* set the source index to the remaining byte offset and */
+ /* increment the size of each line to account for the dont-care */
+ /* pixel(s). */
+
+ indent = (srcx >> 3);
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+ src_value = (indent | ((srcx & 7) << 26));
+
+ /* PROGRAM THE NORMAL SOURCE CHANNEL REGISTERS */
+ /* We assume that a color pattern is being ROPed with source */
+ /* data if the pattern type is color and the preserve pattern */
+ /* was set. */
+
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_OFF_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE |
+ GP3_BLT_HDR_RASTER_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ if (gp3_ch3_pat) {
+ gp3_cmd_header |=
+ GP3_BLT_HDR_CH3_OFF_ENABLE | GP3_BLT_HDR_CH3_WIDHI_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, (dstoffset & 0x3FFFFF));
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, gp3_pat_format);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, size);
+ } else {
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET,
+ ((dstoffset & 0x3FFFFF) | gp3_pat_origin));
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, 0);
+ }
+ if (gp3_blt_flags & CIMGP_BLTFLAGS_INVERTMONO) {
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_raster_mode | GP3_RM_SOURCE_INVERT);
+ } else {
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_raster_mode & ~GP3_RM_SOURCE_INVERT);
+ }
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET, src_value);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET,
+ ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)));
+ WRITE_COMMAND32(GP3_BLT_MODE,
+ gp3_blt_mode | GP3_BM_SRC_HOST | GP3_BM_SRC_MONO);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* CALCULATE THE SIZE OF ONE LINE */
+
+ size = ((width + (srcx & 7) + 7) >> 3) + indent;
+ total_dwords = (size + 3) >> 2;
+ size_dwords = (total_dwords << 2) + 8;
+ dword_count = (size >> 2);
+ byte_count = (size & 3);
+
+ /* CHECK FOR SMALL BLT CASE */
+ /* If the total amount of monochrome data is less than 50K and we have */
+ /* room in the command buffer, we will do all data writes in a single */
+ /* data packet. */
+
+ if (((total_dwords << 2) * height) <= GP3_BLT_1PASS_SIZE &&
+ (gp3_cmd_bottom - gp3_cmd_current) > (GP3_BLT_1PASS_SIZE + 72)) {
+ /* UPDATE THE COMMAND POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + ((total_dwords << 2) * height) + 8;
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_HOST_SOURCE_TYPE | (total_dwords * height));
+
+ while (height--) {
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ srcoffset += stride;
+ cim_cmd_ptr += total_dwords << 2;
+ }
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ } else {
+ /* WRITE DATA LINE BY LINE
+ * Each line will be created as a separate command buffer entry to
+ * allow line-by-line wrapping and to allow simultaneous rendering
+ * by the HW.
+ */
+
+ while (height--) {
+ /* UPDATE THE COMMAND POINTER
+ * The WRITE_COMMANDXX macros use a pointer to the current buffer
+ * space. This is created by adding gp3_cmd_current to the base
+ * pointer.
+ */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + size_dwords;
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ /* WAIT FOR HARDWARE */
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_HOST_SOURCE_TYPE | total_dwords);
+
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ /* UPDATE POINTERS */
+
+ srcoffset += stride;
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_text_blt
+ *
+ * This routine expands and BLTs byte-packed monochrome data to the screen.
+ * There is assumed to be no x clipping involved in the BLT.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_text_blt(unsigned long dstoffset, unsigned long width,
+ unsigned long height, unsigned char *data)
+{
+ unsigned long temp, dwords_total;
+ unsigned long dword_count, byte_count;
+ unsigned long size = ((width << 16) | height);
+ unsigned long srcoffset = 0;
+
+ /* PROGRAM THE NORMAL SOURCE CHANNEL REGISTERS */
+ /* We assume that a color pattern is being ROPed with source */
+ /* data if the pattern type is color and the preserve pattern */
+ /* was set. */
+
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_OFF_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE |
+ GP3_BLT_HDR_RASTER_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ if (gp3_ch3_pat) {
+ gp3_cmd_header |=
+ GP3_BLT_HDR_CH3_OFF_ENABLE | GP3_BLT_HDR_CH3_WIDHI_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, (dstoffset & 0x3FFFFF));
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, gp3_pat_format);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, size);
+ } else {
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET,
+ ((dstoffset & 0x3FFFFF) | gp3_pat_origin));
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, 0);
+ }
+ if (gp3_blt_flags & CIMGP_BLTFLAGS_INVERTMONO) {
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_raster_mode | GP3_RM_SOURCE_INVERT);
+ } else {
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_raster_mode & ~GP3_RM_SOURCE_INVERT);
+ }
+
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET, 0);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET,
+ ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)));
+ WRITE_COMMAND32(GP3_BLT_MODE,
+ gp3_blt_mode | GP3_BM_SRC_HOST | GP3_BM_SRC_BP_MONO);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* CALCULATE THE TOTAL NUMBER OF BYTES */
+
+ size = ((width + 7) >> 3) * height;
+
+ /* WRITE ALL DATA IN CHUNKS */
+
+ do {
+ /* UPDATE THE COMMAND POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ if (size > 8192) {
+ dword_count = 2048;
+ byte_count = 0;
+ dwords_total = 2048;
+ size -= 8192;
+ } else {
+ dword_count = (size >> 2);
+ byte_count = (size & 3);
+ dwords_total = (size + 3) >> 2;
+ size = 0;
+ }
+ gp3_cmd_next = gp3_cmd_current + (dwords_total << 2) + 8;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ /* WAIT FOR HARDWARE */
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_HOST_SOURCE_TYPE | dwords_total);
+
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* UPDATE THE SOURCE OFFSET */
+ /* We add a constant value because the code will loop only if the */
+ /* data exceeds 8192 bytes. */
+
+ srcoffset += 8192;
+
+ } while (size);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_mono_expand_blt
+ *
+ * This routine expands monochrome data that is stored in video memory into
+ * the current BPP. The source and destination regions are assumed not to
+ * overlap. The pitch of the source data is specified in gp_set_strides.
+ * 'srcy' is deliberately omitted to prevent extra calculations for simple
+ * applications that have no source indexes.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_mono_expand_blt(unsigned long dstoffset, unsigned long srcoffset,
+ unsigned long srcx, unsigned long width,
+ unsigned long height, int byte_packed)
+{
+ unsigned long base;
+ unsigned long blt_mode;
+ unsigned long size = ((width << 16) | height);
+
+ /* ADJUST SOURCE OFFSET */
+
+ srcoffset += (srcx >> 3);
+ srcx &= 7;
+
+ /* CALCULATE BASE OFFSET REGISTER */
+
+ base = ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)) |
+ ((gp3_fb_base << 14) + ((srcoffset & 0xFFC00000) >> 10)) |
+ (gp3_base_register & GP3_BASE_OFFSET_CH3MASK);
+
+ /* SET THE SOURCE TYPE */
+
+ if (byte_packed)
+ blt_mode = gp3_blt_mode | GP3_BM_SRC_FB | GP3_BM_SRC_BP_MONO;
+ else
+ blt_mode = gp3_blt_mode | GP3_BM_SRC_FB | GP3_BM_SRC_MONO;
+
+ /* SET HEADER ENABLES */
+
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_OFF_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE |
+ GP3_BLT_HDR_RASTER_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ /* ENABLE COLOR PATTERN IF APPLICABLE */
+
+ if (gp3_ch3_pat) {
+ gp3_cmd_header |=
+ GP3_BLT_HDR_CH3_OFF_ENABLE | GP3_BLT_HDR_CH3_WIDHI_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, gp3_pat_origin);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, (dstoffset & 0x3FFFFF));
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, gp3_pat_format);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, size);
+ } else {
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET,
+ ((dstoffset & 0x3FFFFF) | gp3_pat_origin));
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, 0);
+ }
+ if (gp3_blt_flags & CIMGP_BLTFLAGS_INVERTMONO) {
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_raster_mode | GP3_RM_SOURCE_INVERT);
+ } else {
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_raster_mode & ~GP3_RM_SOURCE_INVERT);
+ }
+
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET,
+ (srcoffset & 0x3FFFFF) | (srcx << 26));
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+
+ /* WORKAROUND FOR SIBZ #3744
+ * Under extremely rare conditions, very narrow byte-packed mono BLTs
+ * can hang the GP. Even under the rare case, the bad condition will
+ * only happen once every 16 lines. The workaround is to break the
+ * offending BLT into a series of safer BLTs. This method is preferred
+ * over a two-pass approach because it does not require saving and
+ * restoring any GP state, such as the ROP or mono colors.
+ */
+
+ if ((gp3_blt_mode & GP3_BM_DST_REQ) && byte_packed && (gp3_pix_shift < 2)
+ && (width < 5) && ((srcoffset & 0x1F) == 0x1F)
+ && ((srcx + width) > 8)) {
+ unsigned long dstoff1, size1, org1;
+ unsigned long dstoff2, size2, org2;
+ unsigned long tempheight;
+
+ size1 = ((8 - srcx) << 16) | 1;
+ size2 = ((width + srcx - 8) << 16) | 1;
+ org1 = gp3_pat_origin;
+ org2 = (org1 & 0xE0000000) |
+ ((org1 + ((8 - srcx) << 26)) & 0x1C000000);
+ dstoff1 = dstoffset & 0x3FFFFF;
+ dstoff2 = (dstoff1 + 8 - srcx) << gp3_pix_shift;
+
+ while (height) {
+ /* DIVIDE THE FIRST LINE INTO TWO SINGLE LINE BLTS */
+
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size1);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, size1);
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET,
+ (srcoffset & 0x3FFFFF) | (srcx << 26));
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, dstoff1 | org1);
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, org1);
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_BLT_MODE, blt_mode);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ gp_wait_until_idle();
+
+ gp_declare_blt(gp3_blt_flags);
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_OFF_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_BLT_MODE_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE | GP3_BLT_HDR_CH3_WIDHI_ENABLE;
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size2);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, size2);
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET, ((srcoffset + 1) & 0x3FFFFF));
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, dstoff2 | org2);
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, org2);
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_BLT_MODE, blt_mode);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ gp_wait_until_idle();
+
+ if (--height) {
+ org1 += 0x20000000;
+ org2 += 0x20000000;
+ dstoff1 += gp3_dst_stride;
+ dstoff2 += gp3_dst_stride;
+ srcoffset += 2;
+
+ /* THE NEXT 15 LINES ARE NOW 'SAFE' - THEY DO NOT SHOW THE
+ * PROBLEM */
+
+ tempheight = 15;
+ if (tempheight > height)
+ tempheight = height;
+
+ gp_declare_blt(gp3_blt_flags);
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_OFF_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_BLT_MODE_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE | GP3_BLT_HDR_CH3_WIDHI_ENABLE;
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT,
+ (width << 16) | tempheight);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI,
+ (width << 16) | tempheight);
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET,
+ (srcoffset & 0x3FFFFF) | (srcx << 26));
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, dstoff1 | org1);
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, org1);
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_BLT_MODE, blt_mode);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ gp_wait_until_idle();
+
+ height -= tempheight;
+
+ if (height) {
+ gp_declare_blt(gp3_blt_flags);
+ gp3_cmd_header |= GP3_BLT_HDR_SRC_OFF_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_BLT_MODE_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE;
+
+ /* ADJUST ORIGIN */
+ /* If we get here, we added a full 15 lines which is
+ * equivalent to subtracting one from the pattern y origin
+ * (adding 15). */
+
+ org1 -= 0x20000000;
+ org2 -= 0x20000000;
+ dstoff1 += (gp3_dst_stride * 15);
+ dstoff2 += (gp3_dst_stride * 15);
+ srcoffset += 30;
+ }
+ }
+ }
+ return;
+ }
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_BLT_MODE, blt_mode);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_antialiased_text
+ *
+ * This routine implements alpha blending between a constant source color and
+ * a destination region. The degree of the blend is controlled by an array
+ * of 4BPP/8BPP values specified in 'data'. 'stride' indicates the pitch
+ * between successive lines of blend data. 'srcx' indicates the x
+ * coordinate within each line of blend data corresponding to the first
+ * pixel. A y coordinate for the source is deliberately omitted to avoid
+ * extra calculation for simple cases that have no y index. The calling
+ * program must adjust the data pointer accordingly. 'fourbpp' selects
+ * between 4BPP and 8BPP alpha.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_antialiased_text(unsigned long dstoffset, unsigned long srcx,
+ unsigned long width, unsigned long height,
+ unsigned char *data, long stride, int fourbpp)
+{
+ unsigned long indent, temp;
+ unsigned long total_dwords, size_dwords;
+ unsigned long dword_count, byte_count;
+ unsigned long size = ((width << 16) | height);
+ unsigned long ch3_offset, srcoffset;
+ unsigned long base, depth_flag;
+
+ base = ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)) |
+ (gp3_base_register & ~GP3_BASE_OFFSET_DSTMASK);
+
+ /* ENABLE ALL RELEVANT REGISTERS */
+ /* We override the raster mode register to force the */
+ /* correct alpha blend */
+
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ /* CALCULATIONS BASED ON ALPHA DEPTH */
+ /* Although most antialiased text is 4BPP, the hardware supports */
+ /* a full 8BPP. Either case is supported by this routine. */
+
+ if (fourbpp) {
+ depth_flag = GP3_CH3_SRC_4BPP_ALPHA;
+ indent = (srcx >> 1);
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+ ch3_offset = indent | ((srcx & 1) << 25);
+
+ temp = ((width + (srcx & 1) + 1) >> 1) + indent;
+ } else {
+ depth_flag = GP3_CH3_SRC_8BPP_ALPHA;
+ indent = srcx;
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+ ch3_offset = indent;
+
+ temp = width + indent;
+ }
+
+ total_dwords = (temp + 3) >> 2;
+ size_dwords = (total_dwords << 2) + 8;
+ dword_count = (temp >> 2);
+ byte_count = (temp & 3);
+
+ /* SET RASTER MODE REGISTER */
+ /* Alpha blending will only apply to RGB when no alpha component is present. */
+ /* As 8BPP is not supported for this routine, the only alpha-less mode is */
+ /* 5:6:5. */
+
+ if (gp3_bpp == GP3_RM_BPPFMT_565) {
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_bpp |
+ GP3_RM_ALPHA_TO_RGB |
+ GP3_RM_ALPHA_A_PLUS_BETA_B | GP3_RM_SELECT_ALPHA_CHAN_3);
+ } else {
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_bpp |
+ GP3_RM_ALPHA_ALL |
+ GP3_RM_ALPHA_A_PLUS_BETA_B | GP3_RM_SELECT_ALPHA_CHAN_3);
+ }
+
+ /* WRITE ALL REMAINING REGISTERS */
+
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, (dstoffset & 0x3FFFFF));
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, ch3_offset);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, size);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, size);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, GP3_CH3_C3EN |
+ GP3_CH3_HST_SRC_ENABLE |
+ depth_flag | ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20));
+ WRITE_COMMAND32(GP3_BLT_MODE, gp3_blt_mode | GP3_BM_DST_REQ);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* WRITE DATA LINE BY LINE
+ * Each line will be created as a separate command buffer entry to allow
+ * line-by-line wrapping and to allow simultaneous rendering by the HW.
+ */
+
+ if (((total_dwords << 2) * height) <= GP3_BLT_1PASS_SIZE &&
+ (gp3_cmd_bottom - gp3_cmd_current) > (GP3_BLT_1PASS_SIZE + 72)) {
+ /* UPDATE THE COMMAND POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + ((total_dwords << 2) * height) + 8;
+
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4,
+ GP3_CH3_HOST_SOURCE_TYPE | (total_dwords * height));
+
+ while (height--) {
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ srcoffset += stride;
+ cim_cmd_ptr += total_dwords << 2;
+ }
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ } else {
+ while (height--) {
+ /* UPDATE THE COMMAND POINTER
+ * The WRITE_COMMANDXX macros use a pointer to the current buffer
+ * space. This is created by adding gp3_cmd_current to the base
+ * pointer.
+ */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + size_dwords;
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ /* WAIT FOR HARDWARE */
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_CH3_HOST_SOURCE_TYPE | total_dwords);
+
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ /* UPDATE POINTERS */
+
+ srcoffset += stride;
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_masked_blt
+ *
+ * This routine copies source data to the screen. A monochrome mask is used
+ * to specify source transparency.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_masked_blt(unsigned long dstoffset, unsigned long width,
+ unsigned long height, unsigned long mono_srcx,
+ unsigned long color_srcx, unsigned char *mono_mask,
+ unsigned char *color_data, long mono_pitch, long color_pitch)
+{
+ unsigned long indent, temp;
+ unsigned long total_dwords, size_dwords;
+ unsigned long dword_count, byte_count;
+ unsigned long srcoffset, size;
+ unsigned long i, ch3_offset, base;
+ unsigned long flags = 0;
+
+ if (gp3_blt_flags & CIMGP_BLTFLAGS_INVERTMONO)
+ flags = GP3_RM_SOURCE_INVERT;
+
+ /* MONO CALCULATIONS */
+
+ indent = (mono_srcx >> 3);
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+
+ size = ((width + (mono_srcx & 7) + 7) >> 3) + indent;
+ total_dwords = (size + 3) >> 2;
+ size_dwords = (total_dwords << 2) + 8;
+ dword_count = (size >> 2);
+ byte_count = (size & 3);
+
+ base = ((gp3_fb_base << 24) + (gp3_scratch_base & 0xFFC00000)) |
+ (gp3_base_register & ~GP3_BASE_OFFSET_DSTMASK);
+
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE |
+ GP3_BLT_HDR_STRIDE_ENABLE | GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_WIDHI_ENABLE | GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE | GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE, GP3_RM_BPPFMT_8888 | 0xCC);
+ WRITE_COMMAND32(GP3_BLT_STRIDE, (total_dwords << 2));
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, gp3_scratch_base & 0x3FFFFF);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, (total_dwords << 16) | height);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, (total_dwords << 16) | height);
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, 0);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, GP3_CH3_C3EN |
+ GP3_CH3_REPLACE_SOURCE | GP3_CH3_HST_SRC_ENABLE |
+ GP3_CH3_SRC_8_8_8_8 |
+ ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20));
+ WRITE_COMMAND32(GP3_BLT_MODE, 0);
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+
+ /* START THE BLT */
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ for (i = 0; i < height; i++) {
+ /* UPDATE THE COMMAND POINTER
+ * The WRITE_COMMANDXX macros use a pointer to the current buffer
+ * space. This is created by adding gp3_cmd_current to the base
+ * pointer.
+ */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + size_dwords;
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ /* WAIT FOR HARDWARE */
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0, GP3_DATA_LOAD_HDR_TYPE |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_CH3_HOST_SOURCE_TYPE | total_dwords);
+
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, mono_mask, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), mono_mask,
+ srcoffset + (dword_count << 2), byte_count);
+
+ /* UPDATE POINTERS */
+
+ srcoffset += mono_pitch;
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ }
+
+ /* SECOND BLT */
+
+ gp_declare_blt(gp3_blt_flags | CIMGP_BLTFLAGS_HAZARD);
+
+ base = ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)) |
+ ((gp3_fb_base << 14) + (((gp3_scratch_base +
+ indent) & 0xFFC00000) >> 10)) | (gp3_base_register &
+ GP3_BASE_OFFSET_CH3MASK);
+
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE |
+ GP3_BLT_HDR_STRIDE_ENABLE | GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_SRC_OFF_ENABLE | GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ /* ENABLE TRANSPARENCY AND PATTERN COPY ROP
+ * The monochrome data is used as a mask but is otherwise not involved in
+ * the BLT. The color data is routed through the pattern channel.
+ */
+
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_bpp | 0xF0 | GP3_RM_SRC_TRANS | flags);
+ WRITE_COMMAND32(GP3_BLT_STRIDE, (total_dwords << 18) | gp3_dst_stride);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, dstoffset & 0x3FFFFF);
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET,
+ ((gp3_scratch_base + indent) & 0x3FFFFF) | ((mono_srcx & 7) << 26));
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, (width << 16) | height);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, (width << 16) | height);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+
+ /* PROGRAM PARAMETERS FOR COLOR SOURCE DATA */
+ /* Data may be color converted along the way. */
+
+ if ((gp3_src_format & GP3_CH3_SRC_MASK) == GP3_CH3_SRC_24BPP_PACKED) {
+ srcoffset = color_srcx * 3;
+ ch3_offset = 0;
+ size = width * 3;
+
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI,
+ (((size + 3) >> 2) << 16) | height);
+ } else if (gp3_src_pix_shift == 3) {
+ /* CALCULATE INDENT AND SOURCE OFFSET */
+
+ indent = (color_srcx >> 1);
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+ ch3_offset = indent | ((color_srcx & 1) << 25);
+
+ size = ((width + (color_srcx & 1) + 1) >> 1) + indent;
+ } else {
+ indent = (color_srcx << gp3_src_pix_shift);
+ srcoffset = (indent & ~3L);
+ indent &= 3;
+ ch3_offset = indent;
+
+ size = (width << gp3_src_pix_shift) + indent;
+ }
+
+ total_dwords = (size + 3) >> 2;
+ size_dwords = (total_dwords << 2) + 8;
+ dword_count = (size >> 2);
+ byte_count = (size & 3);
+
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, ch3_offset);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, GP3_CH3_C3EN |
+ GP3_CH3_HST_SRC_ENABLE |
+ gp3_src_format | ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20));
+ WRITE_COMMAND32(GP3_BLT_MODE,
+ gp3_blt_mode | GP3_BM_SRC_MONO | GP3_BM_SRC_FB);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* WRITE DATA LINE BY LINE */
+
+ while (height--) {
+ /* UPDATE THE COMMAND POINTER */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + size_dwords;
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_WRAP |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0,
+ GP3_DATA_LOAD_HDR_TYPE | GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_CH3_HOST_SOURCE_TYPE | total_dwords);
+
+ /* WRITE COLOR DATA TO THE COMMAND BUFFER */
+
+ WRITE_COMMAND_STRING32(8, color_data, srcoffset, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), color_data,
+ srcoffset + (dword_count << 2), byte_count);
+
+ /* UPDATE COMMAND BUFFER POINTERS */
+ /* We do this before writing the monochrome data because otherwise */
+ /* the GP could throttle the writes to the host source register */
+ /* waiting for color data. If the command buffer has not been */
+ /* updated to load the color data... */
+
+ srcoffset += color_pitch;
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_screen_to_screen_masked
+ *
+ * This routine performs a screen to screen BLT, using a monochrome mask to
+ * specify source transparency. The source data is assumed to be in the
+ * current destination format and to not overlap the destination.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_screen_to_screen_masked(unsigned long dstoffset, unsigned long srcoffset,
+ unsigned long width, unsigned long height,
+ unsigned long mono_srcx, unsigned char *mono_mask, long mono_pitch)
+{
+ unsigned long indent, temp;
+ unsigned long total_dwords, size_dwords;
+ unsigned long dword_count, byte_count;
+ unsigned long srcoff, size;
+ unsigned long i, base;
+ unsigned long flags = 0;
+
+ if (gp3_blt_flags & CIMGP_BLTFLAGS_INVERTMONO)
+ flags = GP3_RM_SOURCE_INVERT;
+
+ /* MONO CALCULATIONS */
+
+ indent = (mono_srcx >> 3);
+ srcoff = (indent & ~3L);
+ indent &= 3;
+
+ size = ((width + (mono_srcx & 7) + 7) >> 3) + indent;
+ total_dwords = (size + 3) >> 2;
+ size_dwords = (total_dwords << 2) + 8;
+ dword_count = (size >> 2);
+ byte_count = (size & 3);
+
+ base = ((gp3_fb_base << 24) + (gp3_scratch_base & 0xFFC00000)) |
+ (gp3_base_register & ~GP3_BASE_OFFSET_DSTMASK);
+
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE | GP3_BLT_HDR_STRIDE_ENABLE |
+ GP3_BLT_HDR_DST_OFF_ENABLE | GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE | GP3_BLT_HDR_CH3_OFF_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE, GP3_RM_BPPFMT_8888 | 0xCC);
+ WRITE_COMMAND32(GP3_BLT_STRIDE, (total_dwords << 2));
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, gp3_scratch_base & 0x3FFFFF);
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, (total_dwords << 16) | height);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, (total_dwords << 16) | height);
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, 0);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, GP3_CH3_C3EN |
+ GP3_CH3_REPLACE_SOURCE | GP3_CH3_HST_SRC_ENABLE |
+ GP3_CH3_SRC_8_8_8_8 |
+ ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20));
+ WRITE_COMMAND32(GP3_BLT_MODE, 0);
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+
+ /* START THE BLT */
+
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ for (i = 0; i < height; i++) {
+ /* UPDATE THE COMMAND POINTER
+ * The WRITE_COMMANDXX macros use a pointer to the current buffer
+ * space. This is created by adding gp3_cmd_current to the base
+ * pointer.
+ */
+
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ /* CHECK IF A WRAP WILL BE NEEDED */
+
+ gp3_cmd_next = gp3_cmd_current + size_dwords;
+ if ((gp3_cmd_bottom - gp3_cmd_next) <= GP3_MAX_COMMAND_SIZE) {
+ gp3_cmd_next = gp3_cmd_top;
+
+ /* WAIT FOR HARDWARE */
+
+ GP3_WAIT_WRAP(temp);
+ WRITE_COMMAND32(0, GP3_DATA_LOAD_HDR_TYPE |
+ GP3_DATA_LOAD_HDR_WRAP | GP3_DATA_LOAD_HDR_ENABLE);
+ } else {
+ /* WAIT FOR AVAILABLE SPACE */
+
+ GP3_WAIT_PRIMITIVE(temp);
+ WRITE_COMMAND32(0, GP3_DATA_LOAD_HDR_TYPE |
+ GP3_DATA_LOAD_HDR_ENABLE);
+ }
+
+ /* WRITE DWORD COUNT */
+
+ WRITE_COMMAND32(4, GP3_CH3_HOST_SOURCE_TYPE | total_dwords);
+
+ /* WRITE DATA */
+
+ WRITE_COMMAND_STRING32(8, mono_mask, srcoff, dword_count);
+ WRITE_COMMAND_STRING8(8 + (dword_count << 2), mono_mask,
+ srcoff + (dword_count << 2), byte_count);
+
+ /* UPDATE POINTERS */
+
+ srcoff += mono_pitch;
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+ }
+
+ /* SECOND BLT */
+
+ gp_declare_blt(gp3_blt_flags | CIMGP_BLTFLAGS_HAZARD);
+
+ base = ((gp3_fb_base << 24) + (dstoffset & 0xFFC00000)) |
+ ((gp3_fb_base << 14) + (((gp3_scratch_base +
+ indent) & 0xFFC00000) >> 10)) | ((gp3_fb_base << 4) +
+ ((srcoffset & 0xFFC00000) >> 20));
+
+ gp3_cmd_header |= GP3_BLT_HDR_RASTER_ENABLE |
+ GP3_BLT_HDR_STRIDE_ENABLE | GP3_BLT_HDR_DST_OFF_ENABLE |
+ GP3_BLT_HDR_SRC_OFF_ENABLE | GP3_BLT_HDR_WIDHI_ENABLE |
+ GP3_BLT_HDR_CH3_STR_ENABLE |
+ GP3_BLT_HDR_CH3_WIDHI_ENABLE |
+ GP3_BLT_HDR_BASE_OFFSET_ENABLE |
+ GP3_BLT_HDR_CH3_OFF_ENABLE | GP3_BLT_HDR_BLT_MODE_ENABLE;
+
+ /* ENABLE TRANSPARENCY AND PATTERN COPY ROP
+ * The monochrome data is used as a mask but is otherwise not involved
+ * in the BLT. The color data is routed through the pattern channel.
+ */
+
+ WRITE_COMMAND32(GP3_BLT_RASTER_MODE,
+ gp3_bpp | 0xF0 | GP3_RM_SRC_TRANS | flags);
+ WRITE_COMMAND32(GP3_BLT_STRIDE, (total_dwords << 18) | gp3_dst_stride);
+ WRITE_COMMAND32(GP3_BLT_DST_OFFSET, dstoffset & 0x3FFFFF);
+ WRITE_COMMAND32(GP3_BLT_SRC_OFFSET,
+ ((gp3_scratch_base + indent) & 0x3FFFFF) | ((mono_srcx & 7) << 26));
+ WRITE_COMMAND32(GP3_BLT_WID_HEIGHT, (width << 16) | height);
+ WRITE_COMMAND32(GP3_BLT_CH3_WIDHI, (width << 16) | height);
+ WRITE_COMMAND32(GP3_BLT_BASE_OFFSET, base);
+
+ /* PROGRAM PARAMETERS FOR COLOR SOURCE DATA */
+
+ WRITE_COMMAND32(GP3_BLT_CH3_OFFSET, srcoffset & 0x3FFFFF);
+ WRITE_COMMAND32(GP3_BLT_CH3_MODE_STR, GP3_CH3_C3EN | gp3_ch3_bpp |
+ gp3_src_stride | ((gp3_blt_flags & CIMGP_BLTFLAGS_PRES_LUT) << 20));
+ WRITE_COMMAND32(GP3_BLT_MODE,
+ gp3_blt_mode | GP3_BM_SRC_MONO | GP3_BM_SRC_FB);
+
+ /* START THE BLT */
+
+ WRITE_COMMAND32(GP3_BLT_CMD_HEADER, gp3_cmd_header);
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_bresenham_line
+ *
+ * This routine draws a vector using the specified Bresenham parameters.
+ * Currently this file does not support a routine that accepts the two
+ * endpoints of a vector and calculates the Bresenham parameters. If it
+ * ever does, this routine is still required for vectors that have been
+ * clipped.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_bresenham_line(unsigned long dstoffset, unsigned short length,
+ unsigned short initerr, unsigned short axialerr,
+ unsigned short diagerr, unsigned long flags)
+{
+ unsigned long base;
+ long offset;
+
+ /* HANDLE NEGATIVE VECTORS */
+ /* We have to be very careful with vectors that increment negatively */
+ /* Our framebuffer scheme tries to align the destination of every */
+ /* BLT or vector to the nearest 4MB-aligned boundary. This is */
+ /* necessary because the GP only supports offsets up to 16MB, but the */
+ /* framebuffer can be over 128MB. To solve this problem, the GP */
+ /* base address registers are alignable to 4MB regions. However, we */
+ /* cannot simply align the dest offset when the vector goes negative. */
+ /* The vector offset could underflow, causing the offset to jump from */
+ /* near 0 to 16MB. As we cannot accurately determine the last address */
+ /* that will be written in a vector short of walking the algorithm in */
+ /* software, we do a worst case approximation. */
+
+ offset = dstoffset;
+ if (!(flags & CIMGP_POSMAJOR)) {
+ if (flags & CIMGP_YMAJOR)
+ offset -= length * gp3_dst_stride;
+ else
+ offset -= (length << gp3_pix_shift);
+
+ if (offset < 0)
+ offset = 0;
+ }
+ if (!(flags & CIMGP_POSMINOR)) {
+ if (flags & CIMGP_YMAJOR)
+ offset -= (length << gp3_pix_shift);
+ else
+ offset -= length * gp3_dst_stride;
+
+ if (offset < 0)
+ offset = 0;
+ }
+
+ offset &= 0xFFC00000;
+ dstoffset -= offset;
+
+ base = ((gp3_fb_base << 24) + offset) |
+ (gp3_base_register & ~GP3_BASE_OFFSET_DSTMASK);
+
+ /* ENABLE RELEVANT REGISTERS */
+ /* Note that we always enable and write the channel 3 mode, if only */
+ /* to turn it off. Cimarron also always writes the base offset */
+ /* register to allow operation with frame buffers larger than 16MB. */
+
+ gp3_cmd_header |= GP3_VEC_HDR_DST_OFF_ENABLE |
+ GP3_VEC_HDR_VEC_ERR_ENABLE |
+ GP3_VEC_HDR_VEC_LEN_ENABLE |
+ GP3_VEC_HDR_BASE_OFFSET_ENABLE |
+ GP3_VEC_HDR_CH3_STR_ENABLE | GP3_VEC_HDR_VEC_MODE_ENABLE;
+
+ /* WRITE THE REGISTERS COMMON TO ALL PATTERN TYPES */
+ /* The destination base is the frame buffer base plus whatever */
+ /* 4MB segment we happen to be drawing to. */
+
+ WRITE_COMMAND32(GP3_VECTOR_VEC_ERR,
+ (((unsigned long)axialerr << 16) | (unsigned long)diagerr));
+ WRITE_COMMAND32(GP3_VECTOR_VEC_LEN,
+ (((unsigned long)length << 16) | (unsigned long)initerr));
+ WRITE_COMMAND32(GP3_VECTOR_BASE_OFFSET, base);
+
+ /* CHECK VECTOR PATTERN CASE */
+
+ if (gp3_ch3_pat) {
+ /* SET THE SOLID COLOR */
+ /* The color for vector patterns from channel 3 comes from */
+ /* the regular pattern registers. */
+
+ gp3_cmd_header |= GP3_VEC_HDR_PAT_CLR0_ENABLE;
+
+ WRITE_COMMAND32(GP3_VECTOR_PAT_COLOR_0, gp3_vector_pattern_color);
+
+ /* INITIALIZE CHANNEL 3 PARAMETERS
+ * We route the channel 3 output to the old source channel. If the
+ * user sets a ROP that involves source, they will get unexpected
+ * results.
+ */
+
+ WRITE_COMMAND32(GP3_VECTOR_DST_OFFSET, dstoffset);
+ WRITE_COMMAND32(GP3_VECTOR_CH3_MODE_STR,
+ GP3_CH3_C3EN | GP3_CH3_REPLACE_SOURCE |
+ GP3_CH3_COLOR_PAT_ENABLE | GP3_CH3_SRC_8_8_8_8);
+ } else {
+ /* DISABLE CHANNEL 3 AND USE NORMAL PATTERN ORIGINS */
+
+ WRITE_COMMAND32(GP3_VECTOR_CH3_MODE_STR, 0);
+ WRITE_COMMAND32(GP3_VECTOR_DST_OFFSET, (dstoffset | gp3_pat_origin));
+ }
+
+ /* START THE VECTOR */
+
+ WRITE_COMMAND32(GP3_VEC_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_VECTOR_MODE, (gp3_vec_mode | flags));
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* ADD A SECOND VECTOR TO CLEAR THE BYTE ENABLES */
+ /* We set a transparent pattern to clear the byte enables. */
+ /* We then restore the previous pattern. (SiBZ #4001) */
+
+ if (gp3_ch3_pat) {
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ WRITE_COMMAND32(0, GP3_LUT_HDR_TYPE | GP3_LUT_HDR_DATA_ENABLE);
+ WRITE_COMMAND32(4, 0x100);
+ WRITE_COMMAND32(8, (1 | GP3_LUT_DATA_TYPE));
+ WRITE_COMMAND32(12, 0);
+
+ /* DUMMY VECTOR */
+ /* We shouldn't need to write anything but vector mode and the length
+ */
+
+ WRITE_COMMAND32(16, GP3_VEC_HDR_TYPE | GP3_VEC_HDR_VEC_MODE_ENABLE |
+ GP3_VEC_HDR_VEC_LEN_ENABLE);
+ WRITE_COMMAND32(16 + GP3_VECTOR_MODE, (gp3_vec_mode | flags));
+ WRITE_COMMAND32(16 + GP3_VECTOR_VEC_LEN,
+ (1 << 16) | (unsigned long)initerr);
+
+ WRITE_COMMAND32(16 + GP3_VECTOR_COMMAND_SIZE,
+ GP3_LUT_HDR_TYPE | GP3_LUT_HDR_DATA_ENABLE);
+ WRITE_COMMAND32(20 + GP3_VECTOR_COMMAND_SIZE, 0x100);
+ WRITE_COMMAND32(24 + GP3_VECTOR_COMMAND_SIZE,
+ (1 | GP3_LUT_DATA_TYPE));
+ WRITE_COMMAND32(28 + GP3_VECTOR_COMMAND_SIZE, gp3_vec_pat);
+
+ gp3_cmd_current += 32 + GP3_VECTOR_COMMAND_SIZE;
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_line_from_endpoints
+ *
+ * This routine draws a vector from a set of rectangular coordinates. The
+ * rectangle is assumed to use the currently specified destination stride.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_line_from_endpoints(unsigned long dstoffset, unsigned long x0,
+ unsigned long y0, unsigned long x1, unsigned long y1, int inclusive)
+{
+ unsigned long base;
+ unsigned long length;
+ unsigned long flags;
+ unsigned short initerr, axialerr, diagerr;
+ long dx, dy, dmaj, dmin;
+ long offset;
+
+ /* ADJUST DESTINATION OFFSET BASED ON STARTING COORDINATE */
+
+ dstoffset += (x0 << gp3_pix_shift) + (y0 * gp3_dst_stride);
+
+ /* CALCULATE BRESENHAM TERMS */
+
+ dx = (long)x1 - (long)x0;
+ dy = (long)y1 - (long)y0;
+ if (dx < 0)
+ dx = -dx;
+ if (dy < 0)
+ dy = -dy;
+
+ if (dx >= dy) {
+ dmaj = dx;
+ dmin = dy;
+ flags = 0;
+ if (x1 > x0)
+ flags |= CIMGP_POSMAJOR;
+ if (y1 > y0)
+ flags |= CIMGP_POSMINOR;
+ } else {
+ dmaj = dy;
+ dmin = dx;
+ flags = CIMGP_YMAJOR;
+ if (x1 > x0)
+ flags |= CIMGP_POSMINOR;
+ if (y1 > y0)
+ flags |= CIMGP_POSMAJOR;
+ }
+
+ axialerr = (unsigned short)(dmin << 1);
+ diagerr = (unsigned short)((dmin - dmaj) << 1);
+ initerr = (unsigned short)((dmin << 1) - dmaj);
+ if (!(flags & CIMGP_POSMINOR))
+ initerr--;
+
+ /* CHECK FOR NO WORK */
+
+ if (!dmaj)
+ return;
+
+ /* CHECK INCLUSIVE OR EXCLUSIVE */
+ /* An inclusive line can be accomplished by simply adding 1 to the */
+ /* line length. */
+
+ length = dmaj;
+ if (inclusive)
+ length++;
+
+ /* HANDLE NEGATIVE VECTORS */
+
+ offset = dstoffset;
+ if (!(flags & CIMGP_POSMAJOR)) {
+ if (flags & CIMGP_YMAJOR)
+ offset -= length * gp3_dst_stride;
+ else
+ offset -= (length << gp3_pix_shift);
+
+ if (offset < 0)
+ offset = 0;
+ }
+ if (!(flags & CIMGP_POSMINOR)) {
+ if (flags & CIMGP_YMAJOR)
+ offset -= (length << gp3_pix_shift);
+ else
+ offset -= length * gp3_dst_stride;
+
+ if (offset < 0)
+ offset = 0;
+ }
+
+ offset &= 0xFFC00000;
+ dstoffset -= offset;
+
+ base = ((gp3_fb_base << 24) + offset) |
+ (gp3_base_register & ~GP3_BASE_OFFSET_DSTMASK);
+
+ /* ENABLE RELEVANT REGISTERS */
+ /* Note that we always enable and write the channel 3 mode, if only */
+ /* to turn it off. Cimarron also always writes the base offset */
+ /* register to allow operation with frame buffers larger than 16MB. */
+
+ gp3_cmd_header |= GP3_VEC_HDR_DST_OFF_ENABLE |
+ GP3_VEC_HDR_VEC_ERR_ENABLE |
+ GP3_VEC_HDR_VEC_LEN_ENABLE |
+ GP3_VEC_HDR_BASE_OFFSET_ENABLE |
+ GP3_VEC_HDR_CH3_STR_ENABLE | GP3_VEC_HDR_VEC_MODE_ENABLE;
+
+ /* WRITE THE REGISTERS COMMON TO ALL PATTERN TYPES */
+ /* The destination base is the frame buffer base plus whatever */
+ /* 4MB segment we happen to be drawing to. */
+
+ WRITE_COMMAND32(GP3_VECTOR_VEC_ERR,
+ (((unsigned long)axialerr << 16) | (unsigned long)diagerr));
+ WRITE_COMMAND32(GP3_VECTOR_VEC_LEN,
+ (((unsigned long)length << 16) | (unsigned long)initerr));
+ WRITE_COMMAND32(GP3_VECTOR_BASE_OFFSET, base);
+
+ /* CHECK VECTOR PATTERN CASE */
+
+ if (gp3_ch3_pat) {
+ /* SET THE SOLID COLOR */
+ /* The color for vector patterns from channel 3 comes from */
+ /* the regular pattern registers. */
+
+ gp3_cmd_header |= GP3_VEC_HDR_PAT_CLR0_ENABLE;
+
+ WRITE_COMMAND32(GP3_VECTOR_PAT_COLOR_0, gp3_vector_pattern_color);
+
+ /* INITIALIZE CHANNEL 3 PARAMETERS */
+ /* We route the channel 3 output to the old source channel. If the
+ * user sets a ROP that involves source, they will get unexpected
+ * results.
+ */
+
+ WRITE_COMMAND32(GP3_VECTOR_DST_OFFSET, dstoffset);
+ WRITE_COMMAND32(GP3_VECTOR_CH3_MODE_STR,
+ GP3_CH3_C3EN | GP3_CH3_REPLACE_SOURCE |
+ GP3_CH3_COLOR_PAT_ENABLE | GP3_CH3_SRC_8_8_8_8);
+ } else {
+ /* DISABLE CHANNEL 3 AND USE NORMAL PATTERN ORIGINS */
+
+ WRITE_COMMAND32(GP3_VECTOR_CH3_MODE_STR, 0);
+ WRITE_COMMAND32(GP3_VECTOR_DST_OFFSET, (dstoffset | gp3_pat_origin));
+ }
+
+ /* START THE VECTOR */
+
+ WRITE_COMMAND32(GP3_VEC_CMD_HEADER, gp3_cmd_header);
+ WRITE_COMMAND32(GP3_VECTOR_MODE, (gp3_vec_mode | flags));
+ WRITE_GP32(GP3_CMD_WRITE, gp3_cmd_next);
+ gp3_cmd_current = gp3_cmd_next;
+
+ /* ADD A SECOND VECTOR TO CLEAR THE BYTE ENABLES */
+ /* We set a transparent pattern to clear the byte enables. */
+ /* We then restore the previous pattern. (SiBZ #4001) */
+
+ if (gp3_ch3_pat) {
+ cim_cmd_ptr = cim_cmd_base_ptr + gp3_cmd_current;
+
+ WRITE_COMMAND32(0, GP3_LUT_HDR_TYPE | GP3_LUT_HDR_DATA_ENABLE);
+ WRITE_COMMAND32(4, 0x100);
+ WRITE_COMMAND32(8, (1 | GP3_LUT_DATA_TYPE));
+ WRITE_COMMAND32(12, 0);
+
+ /* DUMMY VECTOR */
+ /* We shouldn't need to write anything but vector mode and the length
+ */
+
+ WRITE_COMMAND32(16, GP3_VEC_HDR_TYPE | GP3_VEC_HDR_VEC_MODE_ENABLE |
+ GP3_VEC_HDR_VEC_LEN_ENABLE);
+ WRITE_COMMAND32(16 + GP3_VECTOR_MODE, (gp3_vec_mode | flags));
+ WRITE_COMMAND32(16 + GP3_VECTOR_VEC_LEN,
+ (1 << 16) | (unsigned long)initerr);
+
+ WRITE_COMMAND32(16 + GP3_VECTOR_COMMAND_SIZE,
+ GP3_LUT_HDR_TYPE | GP3_LUT_HDR_DATA_ENABLE);
+ WRITE_COMMAND32(20 + GP3_VECTOR_COMMAND_SIZE, 0x100);
+ WRITE_COMMAND32(24 + GP3_VECTOR_COMMAND_SIZE,
+ (1 | GP3_LUT_DATA_TYPE));
+ WRITE_COMMAND32(28 + GP3_VECTOR_COMMAND_SIZE, gp3_vec_pat);
+
+ gp3_cmd_current += 32 + GP3_VECTOR_COMMAND_SIZE;
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_wait_until_idle
+ *
+ * This routine stalls execution until the GP is no longer actively rendering.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_wait_until_idle(void)
+{
+ unsigned long temp;
+
+ while (((temp = READ_GP32(GP3_BLT_STATUS)) & GP3_BS_BLT_BUSY) ||
+ !(temp & GP3_BS_CB_EMPTY)) {
+ ;
+ }
+}
+
+/*---------------------------------------------------------------------------
+ * gp_test_blt_busy
+ *-------------------------------------------------------------------------*/
+
+int
+gp_test_blt_busy(void)
+{
+ unsigned long temp;
+
+ if (((temp = READ_GP32(GP3_BLT_STATUS)) & GP3_BS_BLT_BUSY) ||
+ !(temp & GP3_BS_CB_EMPTY))
+ return 1;
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_test_blt_pending
+ *-------------------------------------------------------------------------*/
+
+int
+gp_test_blt_pending(void)
+{
+ if ((READ_GP32(GP3_BLT_STATUS)) & GP3_BS_BLT_PENDING)
+ return 1;
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_wait_blt_pending
+ *-------------------------------------------------------------------------*/
+
+void
+gp_wait_blt_pending(void)
+{
+ while ((READ_GP32(GP3_BLT_STATUS)) & GP3_BS_BLT_PENDING) ;
+}
+
+/*---------------------------------------------------------------------------
+ * gp_save_state
+ *
+ * This routine saves all persistent GP information.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_save_state(GP_SAVE_RESTORE * gp_state)
+{
+ Q_WORD msr_value;
+
+ gp_wait_until_idle();
+
+ msr_read64(MSR_DEVICE_GEODELX_GP, MSR_GEODELINK_CONFIG, &msr_value);
+ gp_state->cmd_bottom = READ_GP32(GP3_CMD_BOT) & 0xFFFFFF;
+ gp_state->cmd_top = READ_GP32(GP3_CMD_TOP) & 0xFFFFFF;
+ gp_state->cmd_base = (msr_value.low << 4) & 0xFFF00000;
+ gp_state->base_offset = READ_GP32(GP3_BASE_OFFSET);
+
+ /* RESET THE READ POINTER */
+
+ gp_set_command_buffer_base(gp_state->cmd_base, gp_state->cmd_top,
+ gp_state->cmd_bottom);
+}
+
+/*---------------------------------------------------------------------------
+ * gp_restore_state
+ *
+ * This routine restores all persistent GP information.
+ *-------------------------------------------------------------------------*/
+
+void
+gp_restore_state(GP_SAVE_RESTORE * gp_state)
+{
+ gp_wait_until_idle();
+
+ WRITE_GP32(GP3_BASE_OFFSET, gp_state->base_offset);
+
+ gp_set_command_buffer_base(gp_state->cmd_base, gp_state->cmd_top,
+ gp_state->cmd_bottom);
+}