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