cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

i810_accel.c (12190B)


      1/*-*- linux-c -*-
      2 *  linux/drivers/video/i810_accel.c -- Hardware Acceleration
      3 *
      4 *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
      5 *      All Rights Reserved      
      6 *
      7 *  This file is subject to the terms and conditions of the GNU General Public
      8 *  License. See the file COPYING in the main directory of this archive for
      9 *  more details.
     10 */
     11#include <linux/kernel.h>
     12#include <linux/string.h>
     13#include <linux/fb.h>
     14
     15#include "i810_regs.h"
     16#include "i810.h"
     17#include "i810_main.h"
     18
     19static u32 i810fb_rop[] = {
     20	COLOR_COPY_ROP, /* ROP_COPY */
     21	XOR_ROP         /* ROP_XOR  */
     22};
     23
     24/* Macros */
     25#define PUT_RING(n) {                                        \
     26	i810_writel(par->cur_tail, par->iring.virtual, n);   \
     27        par->cur_tail += 4;                                  \
     28        par->cur_tail &= RING_SIZE_MASK;                     \
     29}                                                                      
     30
     31extern void flush_cache(void);
     32
     33/************************************************************/
     34
     35/* BLT Engine Routines */
     36static inline void i810_report_error(u8 __iomem *mmio)
     37{
     38	printk("IIR     : 0x%04x\n"
     39	       "EIR     : 0x%04x\n"
     40	       "PGTBL_ER: 0x%04x\n"
     41	       "IPEIR   : 0x%04x\n"
     42	       "IPEHR   : 0x%04x\n",
     43	       i810_readw(IIR, mmio),
     44	       i810_readb(EIR, mmio),
     45	       i810_readl(PGTBL_ER, mmio),
     46	       i810_readl(IPEIR, mmio), 
     47	       i810_readl(IPEHR, mmio));
     48}
     49
     50/**
     51 * wait_for_space - check ring buffer free space
     52 * @space: amount of ringbuffer space needed in bytes
     53 * @par: pointer to i810fb_par structure
     54 *
     55 * DESCRIPTION:
     56 * The function waits until a free space from the ringbuffer
     57 * is available 
     58 */	
     59static inline int wait_for_space(struct fb_info *info, u32 space)
     60{
     61	struct i810fb_par *par = info->par;
     62	u32 head, count = WAIT_COUNT, tail;
     63	u8 __iomem *mmio = par->mmio_start_virtual;
     64
     65	tail = par->cur_tail;
     66	while (count--) {
     67		head = i810_readl(IRING + 4, mmio) & RBUFFER_HEAD_MASK;	
     68		if ((tail == head) || 
     69		    (tail > head && 
     70		     (par->iring.size - tail + head) >= space) || 
     71		    (tail < head && (head - tail) >= space)) {
     72			return 0;	
     73		}
     74	}
     75	printk("ringbuffer lockup!!!\n");
     76	i810_report_error(mmio); 
     77	par->dev_flags |= LOCKUP;
     78	info->pixmap.scan_align = 1;
     79	return 1;
     80}
     81
     82/** 
     83 * wait_for_engine_idle - waits for all hardware engines to finish
     84 * @par: pointer to i810fb_par structure
     85 *
     86 * DESCRIPTION:
     87 * This waits for lring(0), iring(1), and batch(3), etc to finish and
     88 * waits until ringbuffer is empty.
     89 */
     90static inline int wait_for_engine_idle(struct fb_info *info)
     91{
     92	struct i810fb_par *par = info->par;
     93	u8 __iomem *mmio = par->mmio_start_virtual;
     94	int count = WAIT_COUNT;
     95
     96	if (wait_for_space(info, par->iring.size)) /* flush */
     97		return 1;
     98
     99	while((i810_readw(INSTDONE, mmio) & 0x7B) != 0x7B && --count); 
    100	if (count) return 0;
    101
    102	printk("accel engine lockup!!!\n");
    103	printk("INSTDONE: 0x%04x\n", i810_readl(INSTDONE, mmio));
    104	i810_report_error(mmio); 
    105	par->dev_flags |= LOCKUP;
    106	info->pixmap.scan_align = 1;
    107	return 1;
    108}
    109
    110/* begin_iring - prepares the ringbuffer 
    111 * @space: length of sequence in dwords
    112 * @par: pointer to i810fb_par structure
    113 *
    114 * DESCRIPTION:
    115 * Checks/waits for sufficient space in ringbuffer of size
    116 * space.  Returns the tail of the buffer
    117 */ 
    118static inline u32 begin_iring(struct fb_info *info, u32 space)
    119{
    120	struct i810fb_par *par = info->par;
    121
    122	if (par->dev_flags & ALWAYS_SYNC) 
    123		wait_for_engine_idle(info);
    124	return wait_for_space(info, space);
    125}
    126
    127/**
    128 * end_iring - advances the buffer
    129 * @par: pointer to i810fb_par structure
    130 *
    131 * DESCRIPTION:
    132 * This advances the tail of the ringbuffer, effectively
    133 * beginning the execution of the graphics instruction sequence.
    134 */
    135static inline void end_iring(struct i810fb_par *par)
    136{
    137	u8 __iomem *mmio = par->mmio_start_virtual;
    138
    139	i810_writel(IRING, mmio, par->cur_tail);
    140}
    141
    142/**
    143 * source_copy_blit - BLIT transfer operation
    144 * @dwidth: width of rectangular graphics data
    145 * @dheight: height of rectangular graphics data
    146 * @dpitch: bytes per line of destination buffer
    147 * @xdir: direction of copy (left to right or right to left)
    148 * @src: address of first pixel to read from
    149 * @dest: address of first pixel to write to
    150 * @from: source address
    151 * @where: destination address
    152 * @rop: raster operation
    153 * @blit_bpp: pixel format which can be different from the 
    154 *            framebuffer's pixelformat
    155 * @par: pointer to i810fb_par structure
    156 *
    157 * DESCRIPTION:
    158 * This is a BLIT operation typically used when doing
    159 * a 'Copy and Paste'
    160 */
    161static inline void source_copy_blit(int dwidth, int dheight, int dpitch, 
    162				    int xdir, int src, int dest, int rop, 
    163				    int blit_bpp, struct fb_info *info)
    164{
    165	struct i810fb_par *par = info->par;
    166
    167	if (begin_iring(info, 24 + IRING_PAD)) return;
    168
    169	PUT_RING(BLIT | SOURCE_COPY_BLIT | 4);
    170	PUT_RING(xdir | rop << 16 | dpitch | DYN_COLOR_EN | blit_bpp);
    171	PUT_RING(dheight << 16 | dwidth);
    172	PUT_RING(dest);
    173	PUT_RING(dpitch);
    174	PUT_RING(src);
    175
    176	end_iring(par);
    177}	
    178
    179/**
    180 * color_blit - solid color BLIT operation
    181 * @width: width of destination
    182 * @height: height of destination
    183 * @pitch: pixels per line of the buffer
    184 * @dest: address of first pixel to write to
    185 * @where: destination
    186 * @rop: raster operation
    187 * @what: color to transfer
    188 * @blit_bpp: pixel format which can be different from the 
    189 *            framebuffer's pixelformat
    190 * @par: pointer to i810fb_par structure
    191 *
    192 * DESCRIPTION:
    193 * A BLIT operation which can be used for  color fill/rectangular fill
    194 */
    195static inline void color_blit(int width, int height, int pitch,  int dest, 
    196			      int rop, int what, int blit_bpp, 
    197			      struct fb_info *info)
    198{
    199	struct i810fb_par *par = info->par;
    200
    201	if (begin_iring(info, 24 + IRING_PAD)) return;
    202
    203	PUT_RING(BLIT | COLOR_BLT | 3);
    204	PUT_RING(rop << 16 | pitch | SOLIDPATTERN | DYN_COLOR_EN | blit_bpp);
    205	PUT_RING(height << 16 | width);
    206	PUT_RING(dest);
    207	PUT_RING(what);
    208	PUT_RING(NOP);
    209
    210	end_iring(par);
    211}
    212 
    213/**
    214 * mono_src_copy_imm_blit - color expand from system memory to framebuffer
    215 * @dwidth: width of destination
    216 * @dheight: height of destination
    217 * @dpitch: pixels per line of the buffer
    218 * @dsize: size of bitmap in double words
    219 * @dest: address of first byte of pixel;
    220 * @rop: raster operation
    221 * @blit_bpp: pixelformat to use which can be different from the 
    222 *            framebuffer's pixelformat
    223 * @src: address of image data
    224 * @bg: backgound color
    225 * @fg: forground color
    226 * @par: pointer to i810fb_par structure
    227 *
    228 * DESCRIPTION:
    229 * A color expand operation where the  source data is placed in the 
    230 * ringbuffer itself. Useful for drawing text. 
    231 *
    232 * REQUIREMENT:
    233 * The end of a scanline must be padded to the next word.
    234 */
    235static inline void mono_src_copy_imm_blit(int dwidth, int dheight, int dpitch,
    236					  int dsize, int blit_bpp, int rop,
    237					  int dest, const u32 *src, int bg,
    238					  int fg, struct fb_info *info)
    239{
    240	struct i810fb_par *par = info->par;
    241
    242	if (begin_iring(info, 24 + (dsize << 2) + IRING_PAD)) return;
    243
    244	PUT_RING(BLIT | MONO_SOURCE_COPY_IMMEDIATE | (4 + dsize));
    245	PUT_RING(DYN_COLOR_EN | blit_bpp | rop << 16 | dpitch);
    246	PUT_RING(dheight << 16 | dwidth);
    247	PUT_RING(dest);
    248	PUT_RING(bg);
    249	PUT_RING(fg);
    250	while (dsize--) 
    251		PUT_RING(*src++);
    252
    253	end_iring(par);
    254}
    255
    256static inline void load_front(int offset, struct fb_info *info)
    257{
    258	struct i810fb_par *par = info->par;
    259
    260	if (begin_iring(info, 8 + IRING_PAD)) return;
    261
    262	PUT_RING(PARSER | FLUSH);
    263	PUT_RING(NOP);
    264
    265	end_iring(par);
    266
    267	if (begin_iring(info, 8 + IRING_PAD)) return;
    268
    269	PUT_RING(PARSER | FRONT_BUFFER | ((par->pitch >> 3) << 8));
    270	PUT_RING((par->fb.offset << 12) + offset);
    271
    272	end_iring(par);
    273}
    274
    275/**
    276 * i810fb_iring_enable - enables/disables the ringbuffer
    277 * @mode: enable or disable
    278 * @par: pointer to i810fb_par structure
    279 *
    280 * DESCRIPTION:
    281 * Enables or disables the ringbuffer, effectively enabling or
    282 * disabling the instruction/acceleration engine.
    283 */
    284static inline void i810fb_iring_enable(struct i810fb_par *par, u32 mode)
    285{
    286	u32 tmp;
    287	u8 __iomem *mmio = par->mmio_start_virtual;
    288
    289	tmp = i810_readl(IRING + 12, mmio);
    290	if (mode == OFF) 
    291		tmp &= ~1;
    292	else 
    293		tmp |= 1;
    294	flush_cache();
    295	i810_writel(IRING + 12, mmio, tmp);
    296}       
    297
    298void i810fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
    299{
    300	struct i810fb_par *par = info->par;
    301	u32 dx, dy, width, height, dest, rop = 0, color = 0;
    302
    303	if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
    304	    par->depth == 4) {
    305		cfb_fillrect(info, rect);
    306		return;
    307	}
    308
    309	if (par->depth == 1) 
    310		color = rect->color;
    311	else 
    312		color = ((u32 *) (info->pseudo_palette))[rect->color];
    313
    314	rop = i810fb_rop[rect->rop];
    315
    316	dx = rect->dx * par->depth;
    317	width = rect->width * par->depth;
    318	dy = rect->dy;
    319	height = rect->height;
    320
    321	dest = info->fix.smem_start + (dy * info->fix.line_length) + dx;
    322	color_blit(width, height, info->fix.line_length, dest, rop, color, 
    323		   par->blit_bpp, info);
    324}
    325	
    326void i810fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) 
    327{
    328	struct i810fb_par *par = info->par;
    329	u32 sx, sy, dx, dy, pitch, width, height, src, dest, xdir;
    330
    331	if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
    332	    par->depth == 4) {
    333		cfb_copyarea(info, region);
    334		return;
    335	}
    336
    337	dx = region->dx * par->depth;
    338	sx = region->sx * par->depth;
    339	width = region->width * par->depth;
    340	sy = region->sy;
    341	dy = region->dy;
    342	height = region->height;
    343
    344	if (dx <= sx) {
    345		xdir = INCREMENT;
    346	}
    347	else {
    348		xdir = DECREMENT;
    349		sx += width - 1;
    350		dx += width - 1;
    351	}
    352	if (dy <= sy) {
    353		pitch = info->fix.line_length;
    354	}
    355	else {
    356		pitch = (-(info->fix.line_length)) & 0xFFFF;
    357		sy += height - 1;
    358		dy += height - 1;
    359	}
    360	src = info->fix.smem_start + (sy * info->fix.line_length) + sx;
    361	dest = info->fix.smem_start + (dy * info->fix.line_length) + dx;
    362
    363	source_copy_blit(width, height, pitch, xdir, src, dest,
    364			 PAT_COPY_ROP, par->blit_bpp, info);
    365}
    366
    367void i810fb_imageblit(struct fb_info *info, const struct fb_image *image)
    368{
    369	struct i810fb_par *par = info->par;
    370	u32 fg = 0, bg = 0, size, dst;
    371	
    372	if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
    373	    par->depth == 4 || image->depth != 1) {
    374		cfb_imageblit(info, image);
    375		return;
    376	}
    377
    378	switch (info->var.bits_per_pixel) {
    379	case 8:
    380		fg = image->fg_color;
    381		bg = image->bg_color;
    382		break;
    383	case 16:
    384	case 24:
    385		fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
    386		bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
    387		break;
    388	}	
    389	
    390	dst = info->fix.smem_start + (image->dy * info->fix.line_length) + 
    391		(image->dx * par->depth);
    392
    393	size = (image->width+7)/8 + 1;
    394	size &= ~1;
    395	size *= image->height;
    396	size += 7;
    397	size &= ~7;
    398	mono_src_copy_imm_blit(image->width * par->depth, 
    399			       image->height, info->fix.line_length, 
    400			       size/4, par->blit_bpp,
    401			       PAT_COPY_ROP, dst, (u32 *) image->data, 
    402			       bg, fg, info);
    403} 
    404
    405int i810fb_sync(struct fb_info *info)
    406{
    407	struct i810fb_par *par = info->par;
    408	
    409	if (!info->var.accel_flags || par->dev_flags & LOCKUP)
    410		return 0;
    411
    412	return wait_for_engine_idle(info);
    413}
    414
    415void i810fb_load_front(u32 offset, struct fb_info *info)
    416{
    417	struct i810fb_par *par = info->par;
    418	u8 __iomem *mmio = par->mmio_start_virtual;
    419
    420	if (!info->var.accel_flags || par->dev_flags & LOCKUP)
    421		i810_writel(DPLYBASE, mmio, par->fb.physical + offset);
    422	else 
    423		load_front(offset, info);
    424}
    425
    426/**
    427 * i810fb_init_ringbuffer - initialize the ringbuffer
    428 * @par: pointer to i810fb_par structure
    429 *
    430 * DESCRIPTION:
    431 * Initializes the ringbuffer by telling the device the
    432 * size and location of the ringbuffer.  It also sets 
    433 * the head and tail pointers = 0
    434 */
    435void i810fb_init_ringbuffer(struct fb_info *info)
    436{
    437	struct i810fb_par *par = info->par;
    438	u32 tmp1, tmp2;
    439	u8 __iomem *mmio = par->mmio_start_virtual;
    440	
    441	wait_for_engine_idle(info);
    442	i810fb_iring_enable(par, OFF);
    443	i810_writel(IRING, mmio, 0);
    444	i810_writel(IRING + 4, mmio, 0);
    445	par->cur_tail = 0;
    446
    447	tmp2 = i810_readl(IRING + 8, mmio) & ~RBUFFER_START_MASK; 
    448	tmp1 = par->iring.physical;
    449	i810_writel(IRING + 8, mmio, tmp2 | tmp1);
    450
    451	tmp1 = i810_readl(IRING + 12, mmio);
    452	tmp1 &= ~RBUFFER_SIZE_MASK;
    453	tmp2 = (par->iring.size - I810_PAGESIZE) & RBUFFER_SIZE_MASK;
    454	i810_writel(IRING + 12, mmio, tmp1 | tmp2);
    455	i810fb_iring_enable(par, ON);
    456}