Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include "radeonfb.h"
0003 
0004 /* the accelerated functions here are patterned after the 
0005  * "ACCEL_MMIO" ifdef branches in XFree86
0006  * --dte
0007  */
0008 
0009 static void radeon_fixup_offset(struct radeonfb_info *rinfo)
0010 {
0011     u32 local_base;
0012 
0013     /* *** Ugly workaround *** */
0014     /*
0015      * On some platforms, the video memory is mapped at 0 in radeon chip space
0016      * (like PPCs) by the firmware. X will always move it up so that it's seen
0017      * by the chip to be at the same address as the PCI BAR.
0018      * That means that when switching back from X, there is a mismatch between
0019      * the offsets programmed into the engine. This means that potentially,
0020      * accel operations done before radeonfb has a chance to re-init the engine
0021      * will have incorrect offsets, and potentially trash system memory !
0022      *
0023      * The correct fix is for fbcon to never call any accel op before the engine
0024      * has properly been re-initialized (by a call to set_var), but this is a
0025      * complex fix. This workaround in the meantime, called before every accel
0026      * operation, makes sure the offsets are in sync.
0027      */
0028 
0029     radeon_fifo_wait (1);
0030     local_base = INREG(MC_FB_LOCATION) << 16;
0031     if (local_base == rinfo->fb_local_base)
0032         return;
0033 
0034     rinfo->fb_local_base = local_base;
0035 
0036     radeon_fifo_wait (3);
0037     OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) |
0038                      (rinfo->fb_local_base >> 10));
0039     OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
0040     OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
0041 }
0042 
0043 static void radeonfb_prim_fillrect(struct radeonfb_info *rinfo, 
0044                    const struct fb_fillrect *region)
0045 {
0046     radeon_fifo_wait(4);  
0047   
0048     OUTREG(DP_GUI_MASTER_CNTL,  
0049         rinfo->dp_gui_master_cntl  /* contains, like GMC_DST_32BPP */
0050                 | GMC_BRUSH_SOLID_COLOR
0051                 | ROP3_P);
0052     if (radeon_get_dstbpp(rinfo->depth) != DST_8BPP)
0053         OUTREG(DP_BRUSH_FRGD_CLR, rinfo->pseudo_palette[region->color]);
0054     else
0055         OUTREG(DP_BRUSH_FRGD_CLR, region->color);
0056     OUTREG(DP_WRITE_MSK, 0xffffffff);
0057     OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
0058 
0059     radeon_fifo_wait(2);
0060     OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL);
0061     OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE));
0062 
0063     radeon_fifo_wait(2);  
0064     OUTREG(DST_Y_X, (region->dy << 16) | region->dx);
0065     OUTREG(DST_WIDTH_HEIGHT, (region->width << 16) | region->height);
0066 }
0067 
0068 void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
0069 {
0070     struct radeonfb_info *rinfo = info->par;
0071     struct fb_fillrect modded;
0072     int vxres, vyres;
0073   
0074     if (info->state != FBINFO_STATE_RUNNING)
0075         return;
0076     if (info->flags & FBINFO_HWACCEL_DISABLED) {
0077         cfb_fillrect(info, region);
0078         return;
0079     }
0080 
0081     radeon_fixup_offset(rinfo);
0082 
0083     vxres = info->var.xres_virtual;
0084     vyres = info->var.yres_virtual;
0085 
0086     memcpy(&modded, region, sizeof(struct fb_fillrect));
0087 
0088     if(!modded.width || !modded.height ||
0089        modded.dx >= vxres || modded.dy >= vyres)
0090         return;
0091   
0092     if(modded.dx + modded.width  > vxres) modded.width  = vxres - modded.dx;
0093     if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
0094 
0095     radeonfb_prim_fillrect(rinfo, &modded);
0096 }
0097 
0098 static void radeonfb_prim_copyarea(struct radeonfb_info *rinfo, 
0099                    const struct fb_copyarea *area)
0100 {
0101     int xdir, ydir;
0102     u32 sx, sy, dx, dy, w, h;
0103 
0104     w = area->width; h = area->height;
0105     dx = area->dx; dy = area->dy;
0106     sx = area->sx; sy = area->sy;
0107     xdir = sx - dx;
0108     ydir = sy - dy;
0109 
0110     if ( xdir < 0 ) { sx += w-1; dx += w-1; }
0111     if ( ydir < 0 ) { sy += h-1; dy += h-1; }
0112 
0113     radeon_fifo_wait(3);
0114     OUTREG(DP_GUI_MASTER_CNTL,
0115         rinfo->dp_gui_master_cntl /* i.e. GMC_DST_32BPP */
0116         | GMC_BRUSH_NONE
0117         | GMC_SRC_DSTCOLOR
0118         | ROP3_S 
0119         | DP_SRC_SOURCE_MEMORY );
0120     OUTREG(DP_WRITE_MSK, 0xffffffff);
0121     OUTREG(DP_CNTL, (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0)
0122             | (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0));
0123 
0124     radeon_fifo_wait(2);
0125     OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL);
0126     OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE));
0127 
0128     radeon_fifo_wait(3);
0129     OUTREG(SRC_Y_X, (sy << 16) | sx);
0130     OUTREG(DST_Y_X, (dy << 16) | dx);
0131     OUTREG(DST_HEIGHT_WIDTH, (h << 16) | w);
0132 }
0133 
0134 
0135 void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
0136 {
0137     struct radeonfb_info *rinfo = info->par;
0138     struct fb_copyarea modded;
0139     u32 vxres, vyres;
0140     modded.sx = area->sx;
0141     modded.sy = area->sy;
0142     modded.dx = area->dx;
0143     modded.dy = area->dy;
0144     modded.width  = area->width;
0145     modded.height = area->height;
0146   
0147     if (info->state != FBINFO_STATE_RUNNING)
0148         return;
0149     if (info->flags & FBINFO_HWACCEL_DISABLED) {
0150         cfb_copyarea(info, area);
0151         return;
0152     }
0153 
0154     radeon_fixup_offset(rinfo);
0155 
0156     vxres = info->var.xres_virtual;
0157     vyres = info->var.yres_virtual;
0158 
0159     if(!modded.width || !modded.height ||
0160        modded.sx >= vxres || modded.sy >= vyres ||
0161        modded.dx >= vxres || modded.dy >= vyres)
0162         return;
0163   
0164     if(modded.sx + modded.width > vxres)  modded.width = vxres - modded.sx;
0165     if(modded.dx + modded.width > vxres)  modded.width = vxres - modded.dx;
0166     if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy;
0167     if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
0168   
0169     radeonfb_prim_copyarea(rinfo, &modded);
0170 }
0171 
0172 void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image)
0173 {
0174     struct radeonfb_info *rinfo = info->par;
0175 
0176     if (info->state != FBINFO_STATE_RUNNING)
0177         return;
0178     radeon_engine_idle();
0179 
0180     cfb_imageblit(info, image);
0181 }
0182 
0183 int radeonfb_sync(struct fb_info *info)
0184 {
0185     struct radeonfb_info *rinfo = info->par;
0186 
0187     if (info->state != FBINFO_STATE_RUNNING)
0188         return 0;
0189     radeon_engine_idle();
0190 
0191     return 0;
0192 }
0193 
0194 void radeonfb_engine_reset(struct radeonfb_info *rinfo)
0195 {
0196     u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
0197     u32 host_path_cntl;
0198 
0199     radeon_engine_flush (rinfo);
0200 
0201     clock_cntl_index = INREG(CLOCK_CNTL_INDEX);
0202     mclk_cntl = INPLL(MCLK_CNTL);
0203 
0204     OUTPLL(MCLK_CNTL, (mclk_cntl |
0205                FORCEON_MCLKA |
0206                FORCEON_MCLKB |
0207                FORCEON_YCLKA |
0208                FORCEON_YCLKB |
0209                FORCEON_MC |
0210                FORCEON_AIC));
0211 
0212     host_path_cntl = INREG(HOST_PATH_CNTL);
0213     rbbm_soft_reset = INREG(RBBM_SOFT_RESET);
0214 
0215     if (IS_R300_VARIANT(rinfo)) {
0216         u32 tmp;
0217 
0218         OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset |
0219                      SOFT_RESET_CP |
0220                      SOFT_RESET_HI |
0221                      SOFT_RESET_E2));
0222         INREG(RBBM_SOFT_RESET);
0223         OUTREG(RBBM_SOFT_RESET, 0);
0224         tmp = INREG(RB2D_DSTCACHE_MODE);
0225         OUTREG(RB2D_DSTCACHE_MODE, tmp | (1 << 17)); /* FIXME */
0226     } else {
0227         OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset |
0228                     SOFT_RESET_CP |
0229                     SOFT_RESET_HI |
0230                     SOFT_RESET_SE |
0231                     SOFT_RESET_RE |
0232                     SOFT_RESET_PP |
0233                     SOFT_RESET_E2 |
0234                     SOFT_RESET_RB);
0235         INREG(RBBM_SOFT_RESET);
0236         OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32)
0237                     ~(SOFT_RESET_CP |
0238                       SOFT_RESET_HI |
0239                       SOFT_RESET_SE |
0240                       SOFT_RESET_RE |
0241                       SOFT_RESET_PP |
0242                       SOFT_RESET_E2 |
0243                       SOFT_RESET_RB));
0244         INREG(RBBM_SOFT_RESET);
0245     }
0246 
0247     OUTREG(HOST_PATH_CNTL, host_path_cntl | HDP_SOFT_RESET);
0248     INREG(HOST_PATH_CNTL);
0249     OUTREG(HOST_PATH_CNTL, host_path_cntl);
0250 
0251     if (!IS_R300_VARIANT(rinfo))
0252         OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);
0253 
0254     OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
0255     OUTPLL(MCLK_CNTL, mclk_cntl);
0256 }
0257 
0258 void radeonfb_engine_init (struct radeonfb_info *rinfo)
0259 {
0260     unsigned long temp;
0261 
0262     /* disable 3D engine */
0263     OUTREG(RB3D_CNTL, 0);
0264 
0265     radeonfb_engine_reset(rinfo);
0266 
0267     radeon_fifo_wait (1);
0268     if (IS_R300_VARIANT(rinfo)) {
0269         OUTREG(RB2D_DSTCACHE_MODE, INREG(RB2D_DSTCACHE_MODE) |
0270                RB2D_DC_AUTOFLUSH_ENABLE |
0271                RB2D_DC_DC_DISABLE_IGNORE_PE);
0272     } else {
0273         /* This needs to be double checked with ATI. Latest X driver
0274          * completely "forgets" to set this register on < r3xx, and
0275          * we used to just write 0 there... I'll keep the 0 and update
0276          * that when we have sorted things out on X side.
0277          */
0278         OUTREG(RB2D_DSTCACHE_MODE, 0);
0279     }
0280 
0281     radeon_fifo_wait (3);
0282     /* We re-read MC_FB_LOCATION from card as it can have been
0283      * modified by XFree drivers (ouch !)
0284      */
0285     rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
0286 
0287     OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) |
0288                      (rinfo->fb_local_base >> 10));
0289     OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
0290     OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
0291 
0292     radeon_fifo_wait (1);
0293 #if defined(__BIG_ENDIAN)
0294     OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN);
0295 #else
0296     OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
0297 #endif
0298     radeon_fifo_wait (2);
0299     OUTREG(DEFAULT_SC_TOP_LEFT, 0);
0300     OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX |
0301                      DEFAULT_SC_BOTTOM_MAX));
0302 
0303     temp = radeon_get_dstbpp(rinfo->depth);
0304     rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
0305 
0306     radeon_fifo_wait (1);
0307     OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
0308                     GMC_BRUSH_SOLID_COLOR |
0309                     GMC_SRC_DATATYPE_COLOR));
0310 
0311     radeon_fifo_wait (7);
0312 
0313     /* clear line drawing regs */
0314     OUTREG(DST_LINE_START, 0);
0315     OUTREG(DST_LINE_END, 0);
0316 
0317     /* set brush color regs */
0318     OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff);
0319     OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000);
0320 
0321     /* set source color regs */
0322     OUTREG(DP_SRC_FRGD_CLR, 0xffffffff);
0323     OUTREG(DP_SRC_BKGD_CLR, 0x00000000);
0324 
0325     /* default write mask */
0326     OUTREG(DP_WRITE_MSK, 0xffffffff);
0327 
0328     radeon_engine_idle ();
0329 }