File Index
Files and directories
Sign in
FILE

sm750_hw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/sm750fb/sm750_hw.c C
  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#ifdef CONFIG_MTRR
 17#include <asm/mtrr.h>
 18#endif
 19#include <linux/platform_device.h>
 20#include <linux/sizes.h>
 21
 22#include "sm750.h"
 23#include "ddk750.h"
 24#include "sm750_accel.h"
 25
 26void __iomem *mmio750;
 27
 28int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
 29{
 30	int ret;
 31
 32	ret = 0;
 33
 34	sm750_dev->vidreg_start = pci_resource_start(pdev, 1);
 35	sm750_dev->vidreg_size = SZ_2M;
 36
 37	pr_info("mmio phyAddr = %lx\n", sm750_dev->vidreg_start);
 38
 39	/* reserve the vidreg space of smi adaptor */
 40	ret = pci_request_region(pdev, 1, "sm750fb");
 41	if (ret) {
 42		pr_err("Can not request PCI regions.\n");
 43		return ret;
 44	}
 45
 46	/* now map mmio and vidmem */
 47	sm750_dev->pvReg =
 48		ioremap(sm750_dev->vidreg_start, sm750_dev->vidreg_size);
 49	if (!sm750_dev->pvReg) {
 50		pr_err("mmio failed\n");
 51		ret = -EFAULT;
 52		goto err_release_region;
 53	}
 54	pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg);
 55
 56	sm750_dev->accel.dpr_base = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1;
 57	sm750_dev->accel.dp_port_base = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1;
 58
 59	mmio750 = sm750_dev->pvReg;
 60	sm750_set_chip_type(sm750_dev->devid, sm750_dev->revid);
 61
 62	sm750_dev->vidmem_start = pci_resource_start(pdev, 0);
 63	/*
 64	 * don't use pdev_resource[x].end - resource[x].start to
 65	 * calculate the resource size, it's only the maximum available
 66	 * size but not the actual size, using
 67	 * @ddk750_get_vm_size function can be safe.
 68	 */
 69	sm750_dev->vidmem_size = ddk750_get_vm_size();
 70	pr_info("video memory phyAddr = %lx, size = %u bytes\n",
 71		sm750_dev->vidmem_start, sm750_dev->vidmem_size);
 72
 73	/* reserve the vidmem space of smi adaptor */
 74	sm750_dev->pvMem =
 75		ioremap_wc(sm750_dev->vidmem_start, sm750_dev->vidmem_size);
 76	if (!sm750_dev->pvMem) {
 77		pr_err("Map video memory failed\n");
 78		ret = -EFAULT;
 79		goto err_unmap_reg;
 80	}
 81	pr_info("video memory vaddr = %p\n", sm750_dev->pvMem);
 82
 83	return 0;
 84
 85err_unmap_reg:
 86	iounmap(sm750_dev->pvReg);
 87err_release_region:
 88	pci_release_region(pdev, 1);
 89	return ret;
 90}
 91
 92int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
 93{
 94	struct init_status *parm;
 95
 96	parm = &sm750_dev->initParm;
 97	if (parm->chip_clk == 0)
 98		parm->chip_clk = (sm750_get_chip_type() == SM750LE) ?
 99					       DEFAULT_SM750LE_CHIP_CLOCK :
100					       DEFAULT_SM750_CHIP_CLOCK;
101
102	if (parm->mem_clk == 0)
103		parm->mem_clk = parm->chip_clk;
104	if (parm->master_clk == 0)
105		parm->master_clk = parm->chip_clk / 3;
106
107	ddk750_init_hw((struct initchip_param *)&sm750_dev->initParm);
108	/* for sm718, open pci burst */
109	if (sm750_dev->devid == 0x718) {
110		poke32(SYSTEM_CTRL,
111		       peek32(SYSTEM_CTRL) | SYSTEM_CTRL_PCI_BURST);
112	}
113
114	if (sm750_get_chip_type() != SM750LE) {
115		unsigned int val;
116		/* does user need CRT? */
117		if (sm750_dev->nocrt) {
118			poke32(MISC_CTRL,
119			       peek32(MISC_CTRL) | MISC_CTRL_DAC_POWER_OFF);
120			/* shut off dpms */
121			val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
122			val |= SYSTEM_CTRL_DPMS_VPHN;
123			poke32(SYSTEM_CTRL, val);
124		} else {
125			poke32(MISC_CTRL,
126			       peek32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF);
127			/* turn on dpms */
128			val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
129			val |= SYSTEM_CTRL_DPMS_VPHP;
130			poke32(SYSTEM_CTRL, val);
131		}
132
133		val = peek32(PANEL_DISPLAY_CTRL) &
134		      ~(PANEL_DISPLAY_CTRL_DUAL_DISPLAY |
135			PANEL_DISPLAY_CTRL_DOUBLE_PIXEL);
136		switch (sm750_dev->pnltype) {
137		case sm750_24TFT:
138			break;
139		case sm750_doubleTFT:
140			val |= PANEL_DISPLAY_CTRL_DOUBLE_PIXEL;
141			break;
142		case sm750_dualTFT:
143			val |= PANEL_DISPLAY_CTRL_DUAL_DISPLAY;
144			break;
145		}
146		poke32(PANEL_DISPLAY_CTRL, val);
147	} else {
148		/*
149		 * for 750LE, no DVI chip initialization
150		 * makes Monitor no signal
151		 *
152		 * Set up GPIO for software I2C to program DVI chip in the
153		 * Xilinx SP605 board, in order to have video signal.
154		 */
155		sm750_sw_i2c_init(0, 1);
156
157		/*
158		 * Customer may NOT use CH7301 DVI chip, which has to be
159		 * initialized differently.
160		 */
161		if (sm750_sw_i2c_read_reg(0xec, 0x4a) == 0x95) {
162			/*
163			 * The following register values for CH7301 are from
164			 * Chrontel app note and our experiment.
165			 */
166			pr_info("yes,CH7301 DVI chip found\n");
167			sm750_sw_i2c_write_reg(0xec, 0x1d, 0x16);
168			sm750_sw_i2c_write_reg(0xec, 0x21, 0x9);
169			sm750_sw_i2c_write_reg(0xec, 0x49, 0xC0);
170			pr_info("okay,CH7301 DVI chip setup done\n");
171		}
172	}
173
174	/* init 2d engine */
175	if (!sm750_dev->accel_off)
176		hw_sm750_init_accel(sm750_dev);
177
178	return 0;
179}
180
181int hw_sm750_output_set_mode(struct lynxfb_output *output,
182			     struct fb_var_screeninfo *var,
183			     struct fb_fix_screeninfo *fix)
184{
185	int ret;
186	enum disp_output disp_set;
187	int channel;
188
189	ret = 0;
190	disp_set = 0;
191	channel = *output->channel;
192
193	if (sm750_get_chip_type() != SM750LE) {
194		if (channel == sm750_primary) {
195			pr_info("primary channel\n");
196			if (output->paths & sm750_panel)
197				disp_set |= do_LCD1_PRI;
198			if (output->paths & sm750_crt)
199				disp_set |= do_CRT_PRI;
200
201		} else {
202			pr_info("secondary channel\n");
203			if (output->paths & sm750_panel)
204				disp_set |= do_LCD1_SEC;
205			if (output->paths & sm750_crt)
206				disp_set |= do_CRT_SEC;
207		}
208		ddk750_set_logical_disp_out(disp_set);
209	} else {
210		/* just open DISPLAY_CONTROL_750LE register bit 3:0 */
211		u32 reg;
212
213		reg = peek32(DISPLAY_CONTROL_750LE);
214		reg |= 0xf;
215		poke32(DISPLAY_CONTROL_750LE, reg);
216	}
217
218	pr_info("ddk setlogicdispout done\n");
219	return ret;
220}
221
222int hw_sm750_crtc_check_mode(struct lynxfb_crtc *crtc,
223			     struct fb_var_screeninfo *var)
224{
225	struct sm750_dev *sm750_dev;
226	struct lynxfb_par *par = container_of(crtc, struct lynxfb_par, crtc);
227
228	sm750_dev = par->dev;
229
230	switch (var->bits_per_pixel) {
231	case 8:
232	case 16:
233		break;
234	case 32:
235		if (sm750_dev->revid == SM750LE_REVISION_ID) {
236			pr_debug("750le do not support 32bpp\n");
237			return -EINVAL;
238		}
239		break;
240	default:
241		return -EINVAL;
242	}
243
244	return 0;
245}
246
247/* set the controller's mode for @crtc charged with @var and @fix parameters */
248int hw_sm750_crtc_set_mode(struct lynxfb_crtc *crtc,
249			   struct fb_var_screeninfo *var,
250			   struct fb_fix_screeninfo *fix)
251{
252	int ret, fmt;
253	u32 reg;
254	struct mode_parameter modparm;
255	enum clock_type clock;
256	struct sm750_dev *sm750_dev;
257	struct lynxfb_par *par;
258
259	ret = 0;
260	par = container_of(crtc, struct lynxfb_par, crtc);
261	sm750_dev = par->dev;
262
263	if (!sm750_dev->accel_off) {
264		/* set 2d engine pixel format according to mode bpp */
265		switch (var->bits_per_pixel) {
266		case 8:
267			fmt = 0;
268			break;
269		case 16:
270			fmt = 1;
271			break;
272		case 32:
273		default:
274			fmt = 2;
275			break;
276		}
277		sm750_hw_set2dformat(&sm750_dev->accel, fmt);
278	}
279
280	/* set timing */
281	modparm.pixel_clock = ps_to_hz(var->pixclock);
282	modparm.vertical_sync_polarity =
283		(var->sync & FB_SYNC_HOR_HIGH_ACT) ? POS : NEG;
284	modparm.horizontal_sync_polarity =
285		(var->sync & FB_SYNC_VERT_HIGH_ACT) ? POS : NEG;
286	modparm.clock_phase_polarity =
287		(var->sync & FB_SYNC_COMP_HIGH_ACT) ? POS : NEG;
288	modparm.horizontal_display_end = var->xres;
289	modparm.horizontal_sync_width = var->hsync_len;
290	modparm.horizontal_sync_start = var->xres + var->right_margin;
291	modparm.horizontal_total = var->xres + var->left_margin +
292				   var->right_margin + var->hsync_len;
293	modparm.vertical_display_end = var->yres;
294	modparm.vertical_sync_height = var->vsync_len;
295	modparm.vertical_sync_start = var->yres + var->lower_margin;
296	modparm.vertical_total = var->yres + var->upper_margin +
297				 var->lower_margin + var->vsync_len;
298
299	/* choose pll */
300	if (crtc->channel != sm750_secondary)
301		clock = PRIMARY_PLL;
302	else
303		clock = SECONDARY_PLL;
304
305	pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock);
306	ret = ddk750_set_mode_timing(&modparm, clock);
307	if (ret) {
308		pr_err("Set mode timing failed\n");
309		goto exit;
310	}
311
312	if (crtc->channel != sm750_secondary) {
313		/* set pitch, offset, width, start address, etc... */
314		poke32(PANEL_FB_ADDRESS,
315		       crtc->o_screen & PANEL_FB_ADDRESS_ADDRESS_MASK);
316
317		reg = var->xres * (var->bits_per_pixel >> 3);
318		/*
319		 * crtc->channel is not equal to par->index on numeric,
320		 * be aware of that
321		 */
322		reg = ALIGN(reg, crtc->line_pad);
323		reg = (reg << PANEL_FB_WIDTH_WIDTH_SHIFT) &
324		      PANEL_FB_WIDTH_WIDTH_MASK;
325		reg |= (fix->line_length & PANEL_FB_WIDTH_OFFSET_MASK);
326		poke32(PANEL_FB_WIDTH, reg);
327
328		reg = ((var->xres - 1) << PANEL_WINDOW_WIDTH_WIDTH_SHIFT) &
329		      PANEL_WINDOW_WIDTH_WIDTH_MASK;
330		reg |= (var->xoffset & PANEL_WINDOW_WIDTH_X_MASK);
331		poke32(PANEL_WINDOW_WIDTH, reg);
332
333		reg = (var->yres_virtual - 1)
334		      << PANEL_WINDOW_HEIGHT_HEIGHT_SHIFT;
335		reg &= PANEL_WINDOW_HEIGHT_HEIGHT_MASK;
336		reg |= (var->yoffset & PANEL_WINDOW_HEIGHT_Y_MASK);
337		poke32(PANEL_WINDOW_HEIGHT, reg);
338
339		poke32(PANEL_PLANE_TL, 0);
340
341		reg = ((var->yres - 1) << PANEL_PLANE_BR_BOTTOM_SHIFT) &
342		      PANEL_PLANE_BR_BOTTOM_MASK;
343		reg |= ((var->xres - 1) & PANEL_PLANE_BR_RIGHT_MASK);
344		poke32(PANEL_PLANE_BR, reg);
345
346		/* set pixel format */
347		reg = peek32(PANEL_DISPLAY_CTRL);
348		poke32(PANEL_DISPLAY_CTRL, reg | (var->bits_per_pixel >> 4));
349	} else {
350		/* not implemented now */
351		poke32(CRT_FB_ADDRESS, crtc->o_screen);
352		reg = var->xres * (var->bits_per_pixel >> 3);
353		/*
354		 * crtc->channel is not equal to par->index on numeric,
355		 * be aware of that
356		 */
357		reg = ALIGN(reg, crtc->line_pad) << CRT_FB_WIDTH_WIDTH_SHIFT;
358		reg &= CRT_FB_WIDTH_WIDTH_MASK;
359		reg |= (fix->line_length & CRT_FB_WIDTH_OFFSET_MASK);
360		poke32(CRT_FB_WIDTH, reg);
361
362		/* SET PIXEL FORMAT */
363		reg = peek32(CRT_DISPLAY_CTRL);
364		reg |= ((var->bits_per_pixel >> 4) &
365			CRT_DISPLAY_CTRL_FORMAT_MASK);
366		poke32(CRT_DISPLAY_CTRL, reg);
367	}
368
369exit:
370	return ret;
371}
372
373int hw_sm750_set_col_reg(struct lynxfb_crtc *crtc, ushort index, ushort red,
374			 ushort green, ushort blue)
375{
376	static unsigned int add[] = { PANEL_PALETTE_RAM, CRT_PALETTE_RAM };
377
378	poke32(add[crtc->channel] + index * 4,
379	       (red << 16) | (green << 8) | blue);
380	return 0;
381}
382
383int hw_sm750le_set_blank(struct lynxfb_output *output, int blank)
384{
385	int dpms, crtdb;
386
387	switch (blank) {
388	case FB_BLANK_UNBLANK:
389		dpms = CRT_DISPLAY_CTRL_DPMS_0;
390		crtdb = 0;
391		break;
392	case FB_BLANK_NORMAL:
393		dpms = CRT_DISPLAY_CTRL_DPMS_0;
394		crtdb = CRT_DISPLAY_CTRL_BLANK;
395		break;
396	case FB_BLANK_VSYNC_SUSPEND:
397		dpms = CRT_DISPLAY_CTRL_DPMS_2;
398		crtdb = CRT_DISPLAY_CTRL_BLANK;
399		break;
400	case FB_BLANK_HSYNC_SUSPEND:
401		dpms = CRT_DISPLAY_CTRL_DPMS_1;
402		crtdb = CRT_DISPLAY_CTRL_BLANK;
403		break;
404	case FB_BLANK_POWERDOWN:
405		dpms = CRT_DISPLAY_CTRL_DPMS_3;
406		crtdb = CRT_DISPLAY_CTRL_BLANK;
407		break;
408	default:
409		return -EINVAL;
410	}
411
412	if (output->paths & sm750_crt) {
413		unsigned int val;
414
415		val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
416		poke32(CRT_DISPLAY_CTRL, val | dpms);
417
418		val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
419		poke32(CRT_DISPLAY_CTRL, val | crtdb);
420	}
421	return 0;
422}
423
424int hw_sm750_set_blank(struct lynxfb_output *output, int blank)
425{
426	unsigned int dpms, pps, crtdb;
427
428	dpms = 0;
429	pps = 0;
430	crtdb = 0;
431
432	switch (blank) {
433	case FB_BLANK_UNBLANK:
434		pr_debug("flag = FB_BLANK_UNBLANK\n");
435		dpms = SYSTEM_CTRL_DPMS_VPHP;
436		pps = PANEL_DISPLAY_CTRL_DATA;
437		break;
438	case FB_BLANK_NORMAL:
439		pr_debug("flag = FB_BLANK_NORMAL\n");
440		dpms = SYSTEM_CTRL_DPMS_VPHP;
441		crtdb = CRT_DISPLAY_CTRL_BLANK;
442		break;
443	case FB_BLANK_VSYNC_SUSPEND:
444		dpms = SYSTEM_CTRL_DPMS_VNHP;
445		crtdb = CRT_DISPLAY_CTRL_BLANK;
446		break;
447	case FB_BLANK_HSYNC_SUSPEND:
448		dpms = SYSTEM_CTRL_DPMS_VPHN;
449		crtdb = CRT_DISPLAY_CTRL_BLANK;
450		break;
451	case FB_BLANK_POWERDOWN:
452		dpms = SYSTEM_CTRL_DPMS_VNHN;
453		crtdb = CRT_DISPLAY_CTRL_BLANK;
454		break;
455	}
456
457	if (output->paths & sm750_crt) {
458		unsigned int val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
459
460		poke32(SYSTEM_CTRL, val | dpms);
461
462		val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
463		poke32(CRT_DISPLAY_CTRL, val | crtdb);
464	}
465
466	if (output->paths & sm750_panel) {
467		unsigned int val = peek32(PANEL_DISPLAY_CTRL);
468
469		val &= ~PANEL_DISPLAY_CTRL_DATA;
470		val |= pps;
471		poke32(PANEL_DISPLAY_CTRL, val);
472	}
473
474	return 0;
475}
476
477void hw_sm750_init_accel(struct sm750_dev *sm750_dev)
478{
479	u32 reg;
480
481	sm750_enable_2d_engine(1);
482
483	if (sm750_get_chip_type() == SM750LE) {
484		reg = peek32(DE_STATE1);
485		reg |= DE_STATE1_DE_ABORT;
486		poke32(DE_STATE1, reg);
487
488		reg = peek32(DE_STATE1);
489		reg &= ~DE_STATE1_DE_ABORT;
490		poke32(DE_STATE1, reg);
491
492	} else {
493		/* engine reset */
494		reg = peek32(SYSTEM_CTRL);
495		reg |= SYSTEM_CTRL_DE_ABORT;
496		poke32(SYSTEM_CTRL, reg);
497
498		reg = peek32(SYSTEM_CTRL);
499		reg &= ~SYSTEM_CTRL_DE_ABORT;
500		poke32(SYSTEM_CTRL, reg);
501	}
502
503	/* call 2d init */
504	sm750_dev->accel.de_init(&sm750_dev->accel);
505}
506
507int hw_sm750le_de_wait(void)
508{
509	int i = 0x10000000;
510	unsigned int mask = DE_STATE2_DE_STATUS_BUSY | DE_STATE2_DE_FIFO_EMPTY |
511			    DE_STATE2_DE_MEM_FIFO_EMPTY;
512
513	while (i--) {
514		unsigned int val = peek32(DE_STATE2);
515
516		if ((val & mask) ==
517		    (DE_STATE2_DE_FIFO_EMPTY | DE_STATE2_DE_MEM_FIFO_EMPTY))
518			return 0;
519	}
520	/* timeout error */
521	return -1;
522}
523
524int hw_sm750_de_wait(void)
525{
526	int i = 0x10000000;
527	unsigned int mask = SYSTEM_CTRL_DE_STATUS_BUSY |
528			    SYSTEM_CTRL_DE_FIFO_EMPTY |
529			    SYSTEM_CTRL_DE_MEM_FIFO_EMPTY;
530
531	while (i--) {
532		unsigned int val = peek32(SYSTEM_CTRL);
533
534		if ((val & mask) ==
535		    (SYSTEM_CTRL_DE_FIFO_EMPTY | SYSTEM_CTRL_DE_MEM_FIFO_EMPTY))
536			return 0;
537	}
538	/* timeout error */
539	return -1;
540}
541
542int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
543			 const struct fb_var_screeninfo *var,
544			 const struct fb_info *info)
545{
546	u32 total;
547	/* check params */
548	if ((var->xoffset + var->xres > var->xres_virtual) ||
549	    (var->yoffset + var->yres > var->yres_virtual)) {
550		return -EINVAL;
551	}
552
553	total = var->yoffset * info->fix.line_length +
554		((var->xoffset * var->bits_per_pixel) >> 3);
555	total += crtc->o_screen;
556	if (crtc->channel == sm750_primary) {
557		poke32(PANEL_FB_ADDRESS,
558		       peek32(PANEL_FB_ADDRESS) |
559			       (total & PANEL_FB_ADDRESS_ADDRESS_MASK));
560	} else {
561		poke32(CRT_FB_ADDRESS,
562		       peek32(CRT_FB_ADDRESS) |
563			       (total & CRT_FB_ADDRESS_ADDRESS_MASK));
564	}
565	return 0;
566}
~/ Read-only file preview.