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

accel.c (14042B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
      4 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
      5
      6 */
      7#include <linux/via-core.h>
      8#include "global.h"
      9
     10/*
     11 * Figure out an appropriate bytes-per-pixel setting.
     12 */
     13static int viafb_set_bpp(void __iomem *engine, u8 bpp)
     14{
     15	u32 gemode;
     16
     17	/* Preserve the reserved bits */
     18	/* Lowest 2 bits to zero gives us no rotation */
     19	gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc;
     20	switch (bpp) {
     21	case 8:
     22		gemode |= VIA_GEM_8bpp;
     23		break;
     24	case 16:
     25		gemode |= VIA_GEM_16bpp;
     26		break;
     27	case 32:
     28		gemode |= VIA_GEM_32bpp;
     29		break;
     30	default:
     31		printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp);
     32		return -EINVAL;
     33	}
     34	writel(gemode, engine + VIA_REG_GEMODE);
     35	return 0;
     36}
     37
     38
     39static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
     40	u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
     41	u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
     42	u32 fg_color, u32 bg_color, u8 fill_rop)
     43{
     44	u32 ge_cmd = 0, tmp, i;
     45	int ret;
     46
     47	if (!op || op > 3) {
     48		printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
     49		return -EINVAL;
     50	}
     51
     52	if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
     53		if (src_x < dst_x) {
     54			ge_cmd |= 0x00008000;
     55			src_x += width - 1;
     56			dst_x += width - 1;
     57		}
     58		if (src_y < dst_y) {
     59			ge_cmd |= 0x00004000;
     60			src_y += height - 1;
     61			dst_y += height - 1;
     62		}
     63	}
     64
     65	if (op == VIA_BITBLT_FILL) {
     66		switch (fill_rop) {
     67		case 0x00: /* blackness */
     68		case 0x5A: /* pattern inversion */
     69		case 0xF0: /* pattern copy */
     70		case 0xFF: /* whiteness */
     71			break;
     72		default:
     73			printk(KERN_WARNING "hw_bitblt_1: Invalid fill rop: "
     74				"%u\n", fill_rop);
     75			return -EINVAL;
     76		}
     77	}
     78
     79	ret = viafb_set_bpp(engine, dst_bpp);
     80	if (ret)
     81		return ret;
     82
     83	if (op != VIA_BITBLT_FILL) {
     84		if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
     85			|| src_y & 0xFFFFF000) {
     86			printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
     87				"x/y %d %d\n", src_x, src_y);
     88			return -EINVAL;
     89		}
     90		tmp = src_x | (src_y << 16);
     91		writel(tmp, engine + 0x08);
     92	}
     93
     94	if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
     95		printk(KERN_WARNING "hw_bitblt_1: Unsupported destination x/y "
     96			"%d %d\n", dst_x, dst_y);
     97		return -EINVAL;
     98	}
     99	tmp = dst_x | (dst_y << 16);
    100	writel(tmp, engine + 0x0C);
    101
    102	if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
    103		printk(KERN_WARNING "hw_bitblt_1: Unsupported width/height "
    104			"%d %d\n", width, height);
    105		return -EINVAL;
    106	}
    107	tmp = (width - 1) | ((height - 1) << 16);
    108	writel(tmp, engine + 0x10);
    109
    110	if (op != VIA_BITBLT_COLOR)
    111		writel(fg_color, engine + 0x18);
    112
    113	if (op == VIA_BITBLT_MONO)
    114		writel(bg_color, engine + 0x1C);
    115
    116	if (op != VIA_BITBLT_FILL) {
    117		tmp = src_mem ? 0 : src_addr;
    118		if (dst_addr & 0xE0000007) {
    119			printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
    120				"address %X\n", tmp);
    121			return -EINVAL;
    122		}
    123		tmp >>= 3;
    124		writel(tmp, engine + 0x30);
    125	}
    126
    127	if (dst_addr & 0xE0000007) {
    128		printk(KERN_WARNING "hw_bitblt_1: Unsupported destination "
    129			"address %X\n", dst_addr);
    130		return -EINVAL;
    131	}
    132	tmp = dst_addr >> 3;
    133	writel(tmp, engine + 0x34);
    134
    135	if (op == VIA_BITBLT_FILL)
    136		tmp = 0;
    137	else
    138		tmp = src_pitch;
    139	if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
    140		printk(KERN_WARNING "hw_bitblt_1: Unsupported pitch %X %X\n",
    141			tmp, dst_pitch);
    142		return -EINVAL;
    143	}
    144	tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3));
    145	writel(tmp, engine + 0x38);
    146
    147	if (op == VIA_BITBLT_FILL)
    148		ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
    149	else {
    150		ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
    151		if (src_mem)
    152			ge_cmd |= 0x00000040;
    153		if (op == VIA_BITBLT_MONO)
    154			ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
    155		else
    156			ge_cmd |= 0x00000001;
    157	}
    158	writel(ge_cmd, engine);
    159
    160	if (op == VIA_BITBLT_FILL || !src_mem)
    161		return 0;
    162
    163	tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
    164		3) >> 2;
    165
    166	for (i = 0; i < tmp; i++)
    167		writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
    168
    169	return 0;
    170}
    171
    172static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
    173	u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
    174	u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
    175	u32 fg_color, u32 bg_color, u8 fill_rop)
    176{
    177	u32 ge_cmd = 0, tmp, i;
    178	int ret;
    179
    180	if (!op || op > 3) {
    181		printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
    182		return -EINVAL;
    183	}
    184
    185	if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
    186		if (src_x < dst_x) {
    187			ge_cmd |= 0x00008000;
    188			src_x += width - 1;
    189			dst_x += width - 1;
    190		}
    191		if (src_y < dst_y) {
    192			ge_cmd |= 0x00004000;
    193			src_y += height - 1;
    194			dst_y += height - 1;
    195		}
    196	}
    197
    198	if (op == VIA_BITBLT_FILL) {
    199		switch (fill_rop) {
    200		case 0x00: /* blackness */
    201		case 0x5A: /* pattern inversion */
    202		case 0xF0: /* pattern copy */
    203		case 0xFF: /* whiteness */
    204			break;
    205		default:
    206			printk(KERN_WARNING "hw_bitblt_2: Invalid fill rop: "
    207				"%u\n", fill_rop);
    208			return -EINVAL;
    209		}
    210	}
    211
    212	ret = viafb_set_bpp(engine, dst_bpp);
    213	if (ret)
    214		return ret;
    215
    216	if (op == VIA_BITBLT_FILL)
    217		tmp = 0;
    218	else
    219		tmp = src_pitch;
    220	if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
    221		printk(KERN_WARNING "hw_bitblt_2: Unsupported pitch %X %X\n",
    222			tmp, dst_pitch);
    223		return -EINVAL;
    224	}
    225	tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
    226	writel(tmp, engine + 0x08);
    227
    228	if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
    229		printk(KERN_WARNING "hw_bitblt_2: Unsupported width/height "
    230			"%d %d\n", width, height);
    231		return -EINVAL;
    232	}
    233	tmp = (width - 1) | ((height - 1) << 16);
    234	writel(tmp, engine + 0x0C);
    235
    236	if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
    237		printk(KERN_WARNING "hw_bitblt_2: Unsupported destination x/y "
    238			"%d %d\n", dst_x, dst_y);
    239		return -EINVAL;
    240	}
    241	tmp = dst_x | (dst_y << 16);
    242	writel(tmp, engine + 0x10);
    243
    244	if (dst_addr & 0xE0000007) {
    245		printk(KERN_WARNING "hw_bitblt_2: Unsupported destination "
    246			"address %X\n", dst_addr);
    247		return -EINVAL;
    248	}
    249	tmp = dst_addr >> 3;
    250	writel(tmp, engine + 0x14);
    251
    252	if (op != VIA_BITBLT_FILL) {
    253		if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
    254			|| src_y & 0xFFFFF000) {
    255			printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
    256				"x/y %d %d\n", src_x, src_y);
    257			return -EINVAL;
    258		}
    259		tmp = src_x | (src_y << 16);
    260		writel(tmp, engine + 0x18);
    261
    262		tmp = src_mem ? 0 : src_addr;
    263		if (dst_addr & 0xE0000007) {
    264			printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
    265				"address %X\n", tmp);
    266			return -EINVAL;
    267		}
    268		tmp >>= 3;
    269		writel(tmp, engine + 0x1C);
    270	}
    271
    272	if (op == VIA_BITBLT_FILL) {
    273		writel(fg_color, engine + 0x58);
    274	} else if (op == VIA_BITBLT_MONO) {
    275		writel(fg_color, engine + 0x4C);
    276		writel(bg_color, engine + 0x50);
    277	}
    278
    279	if (op == VIA_BITBLT_FILL)
    280		ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
    281	else {
    282		ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
    283		if (src_mem)
    284			ge_cmd |= 0x00000040;
    285		if (op == VIA_BITBLT_MONO)
    286			ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
    287		else
    288			ge_cmd |= 0x00000001;
    289	}
    290	writel(ge_cmd, engine);
    291
    292	if (op == VIA_BITBLT_FILL || !src_mem)
    293		return 0;
    294
    295	tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
    296		3) >> 2;
    297
    298	for (i = 0; i < tmp; i++)
    299		writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
    300
    301	return 0;
    302}
    303
    304int viafb_setup_engine(struct fb_info *info)
    305{
    306	struct viafb_par *viapar = info->par;
    307	void __iomem *engine;
    308	u32 chip_name = viapar->shared->chip_info.gfx_chip_name;
    309
    310	engine = viapar->shared->vdev->engine_mmio;
    311	if (!engine) {
    312		printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
    313			"hardware acceleration disabled\n");
    314		return -ENOMEM;
    315	}
    316
    317	switch (chip_name) {
    318	case UNICHROME_CLE266:
    319	case UNICHROME_K400:
    320	case UNICHROME_K800:
    321	case UNICHROME_PM800:
    322	case UNICHROME_CN700:
    323	case UNICHROME_CX700:
    324	case UNICHROME_CN750:
    325	case UNICHROME_K8M890:
    326	case UNICHROME_P4M890:
    327	case UNICHROME_P4M900:
    328		viapar->shared->hw_bitblt = hw_bitblt_1;
    329		break;
    330	case UNICHROME_VX800:
    331	case UNICHROME_VX855:
    332	case UNICHROME_VX900:
    333		viapar->shared->hw_bitblt = hw_bitblt_2;
    334		break;
    335	default:
    336		viapar->shared->hw_bitblt = NULL;
    337	}
    338
    339	viapar->fbmem_free -= CURSOR_SIZE;
    340	viapar->shared->cursor_vram_addr = viapar->fbmem_free;
    341	viapar->fbmem_used += CURSOR_SIZE;
    342
    343	viapar->fbmem_free -= VQ_SIZE;
    344	viapar->shared->vq_vram_addr = viapar->fbmem_free;
    345	viapar->fbmem_used += VQ_SIZE;
    346
    347#if IS_ENABLED(CONFIG_VIDEO_VIA_CAMERA)
    348	/*
    349	 * Set aside a chunk of framebuffer memory for the camera
    350	 * driver.  Someday this driver probably needs a proper allocator
    351	 * for fbmem; for now, we just have to do this before the
    352	 * framebuffer initializes itself.
    353	 *
    354	 * As for the size: the engine can handle three frames,
    355	 * 16 bits deep, up to VGA resolution.
    356	 */
    357	viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2;
    358	viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size;
    359	viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size;
    360	viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
    361#endif
    362
    363	viafb_reset_engine(viapar);
    364	return 0;
    365}
    366
    367void viafb_reset_engine(struct viafb_par *viapar)
    368{
    369	void __iomem *engine = viapar->shared->vdev->engine_mmio;
    370	int highest_reg, i;
    371	u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
    372		vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
    373
    374	/* Initialize registers to reset the 2D engine */
    375	switch (viapar->shared->chip_info.twod_engine) {
    376	case VIA_2D_ENG_M1:
    377		highest_reg = 0x5c;
    378		break;
    379	default:
    380		highest_reg = 0x40;
    381		break;
    382	}
    383	for (i = 0; i <= highest_reg; i += 4)
    384		writel(0x0, engine + i);
    385
    386	/* Init AGP and VQ regs */
    387	switch (chip_name) {
    388	case UNICHROME_K8M890:
    389	case UNICHROME_P4M900:
    390	case UNICHROME_VX800:
    391	case UNICHROME_VX855:
    392	case UNICHROME_VX900:
    393		writel(0x00100000, engine + VIA_REG_CR_TRANSET);
    394		writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
    395		writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
    396		break;
    397
    398	default:
    399		writel(0x00100000, engine + VIA_REG_TRANSET);
    400		writel(0x00000000, engine + VIA_REG_TRANSPACE);
    401		writel(0x00333004, engine + VIA_REG_TRANSPACE);
    402		writel(0x60000000, engine + VIA_REG_TRANSPACE);
    403		writel(0x61000000, engine + VIA_REG_TRANSPACE);
    404		writel(0x62000000, engine + VIA_REG_TRANSPACE);
    405		writel(0x63000000, engine + VIA_REG_TRANSPACE);
    406		writel(0x64000000, engine + VIA_REG_TRANSPACE);
    407		writel(0x7D000000, engine + VIA_REG_TRANSPACE);
    408
    409		writel(0xFE020000, engine + VIA_REG_TRANSET);
    410		writel(0x00000000, engine + VIA_REG_TRANSPACE);
    411		break;
    412	}
    413
    414	/* Enable VQ */
    415	vq_start_addr = viapar->shared->vq_vram_addr;
    416	vq_end_addr = viapar->shared->vq_vram_addr + VQ_SIZE - 1;
    417
    418	vq_start_low = 0x50000000 | (vq_start_addr & 0xFFFFFF);
    419	vq_end_low = 0x51000000 | (vq_end_addr & 0xFFFFFF);
    420	vq_high = 0x52000000 | ((vq_start_addr & 0xFF000000) >> 24) |
    421		((vq_end_addr & 0xFF000000) >> 16);
    422	vq_len = 0x53000000 | (VQ_SIZE >> 3);
    423
    424	switch (chip_name) {
    425	case UNICHROME_K8M890:
    426	case UNICHROME_P4M900:
    427	case UNICHROME_VX800:
    428	case UNICHROME_VX855:
    429	case UNICHROME_VX900:
    430		vq_start_low |= 0x20000000;
    431		vq_end_low |= 0x20000000;
    432		vq_high |= 0x20000000;
    433		vq_len |= 0x20000000;
    434
    435		writel(0x00100000, engine + VIA_REG_CR_TRANSET);
    436		writel(vq_high, engine + VIA_REG_CR_TRANSPACE);
    437		writel(vq_start_low, engine + VIA_REG_CR_TRANSPACE);
    438		writel(vq_end_low, engine + VIA_REG_CR_TRANSPACE);
    439		writel(vq_len, engine + VIA_REG_CR_TRANSPACE);
    440		writel(0x74301001, engine + VIA_REG_CR_TRANSPACE);
    441		writel(0x00000000, engine + VIA_REG_CR_TRANSPACE);
    442		break;
    443	default:
    444		writel(0x00FE0000, engine + VIA_REG_TRANSET);
    445		writel(0x080003FE, engine + VIA_REG_TRANSPACE);
    446		writel(0x0A00027C, engine + VIA_REG_TRANSPACE);
    447		writel(0x0B000260, engine + VIA_REG_TRANSPACE);
    448		writel(0x0C000274, engine + VIA_REG_TRANSPACE);
    449		writel(0x0D000264, engine + VIA_REG_TRANSPACE);
    450		writel(0x0E000000, engine + VIA_REG_TRANSPACE);
    451		writel(0x0F000020, engine + VIA_REG_TRANSPACE);
    452		writel(0x1000027E, engine + VIA_REG_TRANSPACE);
    453		writel(0x110002FE, engine + VIA_REG_TRANSPACE);
    454		writel(0x200F0060, engine + VIA_REG_TRANSPACE);
    455
    456		writel(0x00000006, engine + VIA_REG_TRANSPACE);
    457		writel(0x40008C0F, engine + VIA_REG_TRANSPACE);
    458		writel(0x44000000, engine + VIA_REG_TRANSPACE);
    459		writel(0x45080C04, engine + VIA_REG_TRANSPACE);
    460		writel(0x46800408, engine + VIA_REG_TRANSPACE);
    461
    462		writel(vq_high, engine + VIA_REG_TRANSPACE);
    463		writel(vq_start_low, engine + VIA_REG_TRANSPACE);
    464		writel(vq_end_low, engine + VIA_REG_TRANSPACE);
    465		writel(vq_len, engine + VIA_REG_TRANSPACE);
    466		break;
    467	}
    468
    469	/* Set Cursor Image Base Address */
    470	writel(viapar->shared->cursor_vram_addr, engine + VIA_REG_CURSOR_MODE);
    471	writel(0x0, engine + VIA_REG_CURSOR_POS);
    472	writel(0x0, engine + VIA_REG_CURSOR_ORG);
    473	writel(0x0, engine + VIA_REG_CURSOR_BG);
    474	writel(0x0, engine + VIA_REG_CURSOR_FG);
    475	return;
    476}
    477
    478void viafb_show_hw_cursor(struct fb_info *info, int Status)
    479{
    480	struct viafb_par *viapar = info->par;
    481	u32 temp, iga_path = viapar->iga_path;
    482
    483	temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
    484	switch (Status) {
    485	case HW_Cursor_ON:
    486		temp |= 0x1;
    487		break;
    488	case HW_Cursor_OFF:
    489		temp &= 0xFFFFFFFE;
    490		break;
    491	}
    492	switch (iga_path) {
    493	case IGA2:
    494		temp |= 0x80000000;
    495		break;
    496	case IGA1:
    497	default:
    498		temp &= 0x7FFFFFFF;
    499	}
    500	writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
    501}
    502
    503void viafb_wait_engine_idle(struct fb_info *info)
    504{
    505	struct viafb_par *viapar = info->par;
    506	int loop = 0;
    507	u32 mask;
    508	void __iomem *engine = viapar->shared->vdev->engine_mmio;
    509
    510	switch (viapar->shared->chip_info.twod_engine) {
    511	case VIA_2D_ENG_H5:
    512	case VIA_2D_ENG_M1:
    513		mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 |
    514			      VIA_3D_ENG_BUSY_M1;
    515		break;
    516	default:
    517		while (!(readl(engine + VIA_REG_STATUS) &
    518				VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
    519			loop++;
    520			cpu_relax();
    521		}
    522		mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY;
    523		break;
    524	}
    525
    526	while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) {
    527		loop++;
    528		cpu_relax();
    529	}
    530
    531	if (loop >= MAXLOOP)
    532		printk(KERN_ERR "viafb_wait_engine_idle: not syncing\n");
    533}