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_hw.c (14303B)


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