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

sm750_accel.c (12049B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/module.h>
      3#include <linux/kernel.h>
      4#include <linux/errno.h>
      5#include <linux/string.h>
      6#include <linux/mm.h>
      7#include <linux/slab.h>
      8#include <linux/delay.h>
      9#include <linux/fb.h>
     10#include <linux/ioport.h>
     11#include <linux/init.h>
     12#include <linux/pci.h>
     13#include <linux/vmalloc.h>
     14#include <linux/pagemap.h>
     15#include <linux/console.h>
     16#include <linux/platform_device.h>
     17#include <linux/screen_info.h>
     18
     19#include "sm750.h"
     20#include "sm750_accel.h"
     21static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue)
     22{
     23	writel(regValue, accel->dprBase + offset);
     24}
     25
     26static inline u32 read_dpr(struct lynx_accel *accel, int offset)
     27{
     28	return readl(accel->dprBase + offset);
     29}
     30
     31static inline void write_dpPort(struct lynx_accel *accel, u32 data)
     32{
     33	writel(data, accel->dpPortBase);
     34}
     35
     36void sm750_hw_de_init(struct lynx_accel *accel)
     37{
     38	/* setup 2d engine registers */
     39	u32 reg, clr;
     40
     41	write_dpr(accel, DE_MASKS, 0xFFFFFFFF);
     42
     43	/* dpr1c */
     44	reg =  0x3;
     45
     46	clr = DE_STRETCH_FORMAT_PATTERN_XY |
     47	      DE_STRETCH_FORMAT_PATTERN_Y_MASK |
     48	      DE_STRETCH_FORMAT_PATTERN_X_MASK |
     49	      DE_STRETCH_FORMAT_ADDRESSING_MASK |
     50	      DE_STRETCH_FORMAT_SOURCE_HEIGHT_MASK;
     51
     52	/* DE_STRETCH bpp format need be initialized in setMode routine */
     53	write_dpr(accel, DE_STRETCH_FORMAT,
     54		  (read_dpr(accel, DE_STRETCH_FORMAT) & ~clr) | reg);
     55
     56	/* disable clipping and transparent */
     57	write_dpr(accel, DE_CLIP_TL, 0); /* dpr2c */
     58	write_dpr(accel, DE_CLIP_BR, 0); /* dpr30 */
     59
     60	write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); /* dpr24 */
     61	write_dpr(accel, DE_COLOR_COMPARE, 0);
     62
     63	clr = DE_CONTROL_TRANSPARENCY | DE_CONTROL_TRANSPARENCY_MATCH |
     64		DE_CONTROL_TRANSPARENCY_SELECT;
     65
     66	/* dpr0c */
     67	write_dpr(accel, DE_CONTROL, read_dpr(accel, DE_CONTROL) & ~clr);
     68}
     69
     70/*
     71 * set2dformat only be called from setmode functions
     72 * but if you need dual framebuffer driver,need call set2dformat
     73 * every time you use 2d function
     74 */
     75
     76void sm750_hw_set2dformat(struct lynx_accel *accel, int fmt)
     77{
     78	u32 reg;
     79
     80	/* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */
     81	reg = read_dpr(accel, DE_STRETCH_FORMAT);
     82	reg &= ~DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK;
     83	reg |= ((fmt << DE_STRETCH_FORMAT_PIXEL_FORMAT_SHIFT) &
     84		DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK);
     85	write_dpr(accel, DE_STRETCH_FORMAT, reg);
     86}
     87
     88int sm750_hw_fillrect(struct lynx_accel *accel,
     89		      u32 base, u32 pitch, u32 Bpp,
     90		      u32 x, u32 y, u32 width, u32 height,
     91		      u32 color, u32 rop)
     92{
     93	u32 deCtrl;
     94
     95	if (accel->de_wait() != 0) {
     96		/*
     97		 * int time wait and always busy,seems hardware
     98		 * got something error
     99		 */
    100		pr_debug("De engine always busy\n");
    101		return -1;
    102	}
    103
    104	write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base); /* dpr40 */
    105	write_dpr(accel, DE_PITCH,
    106		  ((pitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
    107		   DE_PITCH_DESTINATION_MASK) |
    108		  (pitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
    109
    110	write_dpr(accel, DE_WINDOW_WIDTH,
    111		  ((pitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
    112		   DE_WINDOW_WIDTH_DST_MASK) |
    113		   (pitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK)); /* dpr44 */
    114
    115	write_dpr(accel, DE_FOREGROUND, color); /* DPR14 */
    116
    117	write_dpr(accel, DE_DESTINATION,
    118		  ((x << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
    119		  (y & DE_DESTINATION_Y_MASK)); /* dpr4 */
    120
    121	write_dpr(accel, DE_DIMENSION,
    122		  ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
    123		  (height & DE_DIMENSION_Y_ET_MASK)); /* dpr8 */
    124
    125	deCtrl = DE_CONTROL_STATUS | DE_CONTROL_LAST_PIXEL |
    126		DE_CONTROL_COMMAND_RECTANGLE_FILL | DE_CONTROL_ROP_SELECT |
    127		(rop & DE_CONTROL_ROP_MASK); /* dpr0xc */
    128
    129	write_dpr(accel, DE_CONTROL, deCtrl);
    130	return 0;
    131}
    132
    133/**
    134 * sm750_hw_copyarea
    135 * @accel: Acceleration device data
    136 * @sBase: Address of source: offset in frame buffer
    137 * @sPitch: Pitch value of source surface in BYTE
    138 * @sx: Starting x coordinate of source surface
    139 * @sy: Starting y coordinate of source surface
    140 * @dBase: Address of destination: offset in frame buffer
    141 * @dPitch: Pitch value of destination surface in BYTE
    142 * @Bpp: Color depth of destination surface
    143 * @dx: Starting x coordinate of destination surface
    144 * @dy: Starting y coordinate of destination surface
    145 * @width: width of rectangle in pixel value
    146 * @height: height of rectangle in pixel value
    147 * @rop2: ROP value
    148 */
    149int sm750_hw_copyarea(struct lynx_accel *accel,
    150		      unsigned int sBase, unsigned int sPitch,
    151		      unsigned int sx, unsigned int sy,
    152		      unsigned int dBase, unsigned int dPitch,
    153		      unsigned int Bpp, unsigned int dx, unsigned int dy,
    154		      unsigned int width, unsigned int height,
    155		      unsigned int rop2)
    156{
    157	unsigned int nDirection, de_ctrl;
    158
    159	nDirection = LEFT_TO_RIGHT;
    160	/* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
    161	de_ctrl = 0;
    162
    163	/* If source and destination are the same surface, need to check for overlay cases */
    164	if (sBase == dBase && sPitch == dPitch) {
    165		/* Determine direction of operation */
    166		if (sy < dy) {
    167			/*  +----------+
    168			 *  |S         |
    169			 *  |   +----------+
    170			 *  |   |      |   |
    171			 *  |   |      |   |
    172			 *  +---|------+   |
    173			 *	|         D|
    174			 *	+----------+
    175			 */
    176
    177			nDirection = BOTTOM_TO_TOP;
    178		} else if (sy > dy) {
    179			/*  +----------+
    180			 *  |D         |
    181			 *  |   +----------+
    182			 *  |   |      |   |
    183			 *  |   |      |   |
    184			 *  +---|------+   |
    185			 *	|         S|
    186			 *	+----------+
    187			 */
    188
    189			nDirection = TOP_TO_BOTTOM;
    190		} else {
    191			/* sy == dy */
    192
    193			if (sx <= dx) {
    194				/* +------+---+------+
    195				 * |S     |   |     D|
    196				 * |      |   |      |
    197				 * |      |   |      |
    198				 * |      |   |      |
    199				 * +------+---+------+
    200				 */
    201
    202				nDirection = RIGHT_TO_LEFT;
    203			} else {
    204			/* sx > dx */
    205
    206				/* +------+---+------+
    207				 * |D     |   |     S|
    208				 * |      |   |      |
    209				 * |      |   |      |
    210				 * |      |   |      |
    211				 * +------+---+------+
    212				 */
    213
    214				nDirection = LEFT_TO_RIGHT;
    215			}
    216		}
    217	}
    218
    219	if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
    220		sx += width - 1;
    221		sy += height - 1;
    222		dx += width - 1;
    223		dy += height - 1;
    224	}
    225
    226	/*
    227	 * Note:
    228	 * DE_FOREGROUND and DE_BACKGROUND are don't care.
    229	 * DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS
    230	 * are set by set deSetTransparency().
    231	 */
    232
    233	/*
    234	 * 2D Source Base.
    235	 * It is an address offset (128 bit aligned)
    236	 * from the beginning of frame buffer.
    237	 */
    238	write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */
    239
    240	/*
    241	 * 2D Destination Base.
    242	 * It is an address offset (128 bit aligned)
    243	 * from the beginning of frame buffer.
    244	 */
    245	write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */
    246
    247	/*
    248	 * Program pitch (distance between the 1st points of two adjacent lines).
    249	 * Note that input pitch is BYTE value, but the 2D Pitch register uses
    250	 * pixel values. Need Byte to pixel conversion.
    251	 */
    252	write_dpr(accel, DE_PITCH,
    253		  ((dPitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
    254		   DE_PITCH_DESTINATION_MASK) |
    255		  (sPitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
    256
    257	/*
    258	 * Screen Window width in Pixels.
    259	 * 2D engine uses this value to calculate the linear address in frame buffer
    260	 * for a given point.
    261	 */
    262	write_dpr(accel, DE_WINDOW_WIDTH,
    263		  ((dPitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
    264		   DE_WINDOW_WIDTH_DST_MASK) |
    265		  (sPitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK)); /* dpr3c */
    266
    267	if (accel->de_wait() != 0)
    268		return -1;
    269
    270	write_dpr(accel, DE_SOURCE,
    271		  ((sx << DE_SOURCE_X_K1_SHIFT) & DE_SOURCE_X_K1_MASK) |
    272		  (sy & DE_SOURCE_Y_K2_MASK)); /* dpr0 */
    273	write_dpr(accel, DE_DESTINATION,
    274		  ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
    275		  (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
    276	write_dpr(accel, DE_DIMENSION,
    277		  ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
    278		  (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
    279
    280	de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) | DE_CONTROL_ROP_SELECT |
    281		((nDirection == RIGHT_TO_LEFT) ? DE_CONTROL_DIRECTION : 0) |
    282		DE_CONTROL_COMMAND_BITBLT | DE_CONTROL_STATUS;
    283	write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */
    284
    285	return 0;
    286}
    287
    288static unsigned int deGetTransparency(struct lynx_accel *accel)
    289{
    290	unsigned int de_ctrl;
    291
    292	de_ctrl = read_dpr(accel, DE_CONTROL);
    293
    294	de_ctrl &= (DE_CONTROL_TRANSPARENCY_MATCH |
    295		    DE_CONTROL_TRANSPARENCY_SELECT | DE_CONTROL_TRANSPARENCY);
    296
    297	return de_ctrl;
    298}
    299
    300/**
    301 * sm750_hw_imageblit
    302 * @accel: Acceleration device data
    303 * @pSrcbuf: pointer to start of source buffer in system memory
    304 * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top down
    305 *	      and -ive mean button up
    306 * @startBit: Mono data can start at any bit in a byte, this value should be
    307 *	      0 to 7
    308 * @dBase: Address of destination: offset in frame buffer
    309 * @dPitch: Pitch value of destination surface in BYTE
    310 * @bytePerPixel: Color depth of destination surface
    311 * @dx: Starting x coordinate of destination surface
    312 * @dy: Starting y coordinate of destination surface
    313 * @width: width of rectangle in pixel value
    314 * @height: height of rectangle in pixel value
    315 * @fColor: Foreground color (corresponding to a 1 in the monochrome data
    316 * @bColor: Background color (corresponding to a 0 in the monochrome data
    317 * @rop2: ROP value
    318 */
    319int sm750_hw_imageblit(struct lynx_accel *accel, const char *pSrcbuf,
    320		       u32 srcDelta, u32 startBit, u32 dBase, u32 dPitch,
    321		       u32 bytePerPixel, u32 dx, u32 dy, u32 width,
    322		       u32 height, u32 fColor, u32 bColor, u32 rop2)
    323{
    324	unsigned int ulBytesPerScan;
    325	unsigned int ul4BytesPerScan;
    326	unsigned int ulBytesRemain;
    327	unsigned int de_ctrl = 0;
    328	unsigned char ajRemain[4];
    329	int i, j;
    330
    331	startBit &= 7; /* Just make sure the start bit is within legal range */
    332	ulBytesPerScan = (width + startBit + 7) / 8;
    333	ul4BytesPerScan = ulBytesPerScan & ~3;
    334	ulBytesRemain = ulBytesPerScan & 3;
    335
    336	if (accel->de_wait() != 0)
    337		return -1;
    338
    339	/*
    340	 * 2D Source Base.
    341	 * Use 0 for HOST Blt.
    342	 */
    343	write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
    344
    345	/* 2D Destination Base.
    346	 * It is an address offset (128 bit aligned)
    347	 * from the beginning of frame buffer.
    348	 */
    349	write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase);
    350
    351	/*
    352	 * Program pitch (distance between the 1st points of two adjacent
    353	 * lines). Note that input pitch is BYTE value, but the 2D Pitch
    354	 * register uses pixel values. Need Byte to pixel conversion.
    355	 */
    356	write_dpr(accel, DE_PITCH,
    357		  ((dPitch / bytePerPixel << DE_PITCH_DESTINATION_SHIFT) &
    358		   DE_PITCH_DESTINATION_MASK) |
    359		  (dPitch / bytePerPixel & DE_PITCH_SOURCE_MASK)); /* dpr10 */
    360
    361	/*
    362	 * Screen Window width in Pixels.
    363	 * 2D engine uses this value to calculate the linear address
    364	 * in frame buffer for a given point.
    365	 */
    366	write_dpr(accel, DE_WINDOW_WIDTH,
    367		  ((dPitch / bytePerPixel << DE_WINDOW_WIDTH_DST_SHIFT) &
    368		   DE_WINDOW_WIDTH_DST_MASK) |
    369		  (dPitch / bytePerPixel & DE_WINDOW_WIDTH_SRC_MASK));
    370
    371	 /*
    372	  * Note: For 2D Source in Host Write, only X_K1_MONO field is needed,
    373	  * and Y_K2 field is not used.
    374	  * For mono bitmap, use startBit for X_K1.
    375	  */
    376	write_dpr(accel, DE_SOURCE,
    377		  (startBit << DE_SOURCE_X_K1_SHIFT) &
    378		  DE_SOURCE_X_K1_MONO_MASK); /* dpr00 */
    379
    380	write_dpr(accel, DE_DESTINATION,
    381		  ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
    382		  (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
    383
    384	write_dpr(accel, DE_DIMENSION,
    385		  ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
    386		  (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
    387
    388	write_dpr(accel, DE_FOREGROUND, fColor);
    389	write_dpr(accel, DE_BACKGROUND, bColor);
    390
    391	de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) |
    392		DE_CONTROL_ROP_SELECT | DE_CONTROL_COMMAND_HOST_WRITE |
    393		DE_CONTROL_HOST | DE_CONTROL_STATUS;
    394
    395	write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel));
    396
    397	/* Write MONO data (line by line) to 2D Engine data port */
    398	for (i = 0; i < height; i++) {
    399		/* For each line, send the data in chunks of 4 bytes */
    400		for (j = 0; j < (ul4BytesPerScan / 4); j++)
    401			write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
    402
    403		if (ulBytesRemain) {
    404			memcpy(ajRemain, pSrcbuf + ul4BytesPerScan,
    405			       ulBytesRemain);
    406			write_dpPort(accel, *(unsigned int *)ajRemain);
    407		}
    408
    409		pSrcbuf += srcDelta;
    410	}
    411
    412	return 0;
    413}
    414