162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
462306a36Sopenharmony_ci * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci/*
862306a36Sopenharmony_ci * basic modesetting functions
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/via-core.h>
1362306a36Sopenharmony_ci#include "via_modesetting.h"
1462306a36Sopenharmony_ci#include "share.h"
1562306a36Sopenharmony_ci#include "debug.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_civoid via_set_primary_timing(const struct via_display_timing *timing)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	struct via_display_timing raw;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	raw.hor_total = timing->hor_total / 8 - 5;
2362306a36Sopenharmony_ci	raw.hor_addr = timing->hor_addr / 8 - 1;
2462306a36Sopenharmony_ci	raw.hor_blank_start = timing->hor_blank_start / 8 - 1;
2562306a36Sopenharmony_ci	raw.hor_blank_end = timing->hor_blank_end / 8 - 1;
2662306a36Sopenharmony_ci	raw.hor_sync_start = timing->hor_sync_start / 8;
2762306a36Sopenharmony_ci	raw.hor_sync_end = timing->hor_sync_end / 8;
2862306a36Sopenharmony_ci	raw.ver_total = timing->ver_total - 2;
2962306a36Sopenharmony_ci	raw.ver_addr = timing->ver_addr - 1;
3062306a36Sopenharmony_ci	raw.ver_blank_start = timing->ver_blank_start - 1;
3162306a36Sopenharmony_ci	raw.ver_blank_end = timing->ver_blank_end - 1;
3262306a36Sopenharmony_ci	raw.ver_sync_start = timing->ver_sync_start - 1;
3362306a36Sopenharmony_ci	raw.ver_sync_end = timing->ver_sync_end - 1;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* unlock timing registers */
3662306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x11, 0x00, 0x80);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	via_write_reg(VIACR, 0x00, raw.hor_total & 0xFF);
3962306a36Sopenharmony_ci	via_write_reg(VIACR, 0x01, raw.hor_addr & 0xFF);
4062306a36Sopenharmony_ci	via_write_reg(VIACR, 0x02, raw.hor_blank_start & 0xFF);
4162306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x03, raw.hor_blank_end & 0x1F, 0x1F);
4262306a36Sopenharmony_ci	via_write_reg(VIACR, 0x04, raw.hor_sync_start & 0xFF);
4362306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x05, (raw.hor_sync_end & 0x1F)
4462306a36Sopenharmony_ci		| (raw.hor_blank_end << (7 - 5) & 0x80), 0x9F);
4562306a36Sopenharmony_ci	via_write_reg(VIACR, 0x06, raw.ver_total & 0xFF);
4662306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x07, (raw.ver_total >> 8 & 0x01)
4762306a36Sopenharmony_ci		| (raw.ver_addr >> (8 - 1) & 0x02)
4862306a36Sopenharmony_ci		| (raw.ver_sync_start >> (8 - 2) & 0x04)
4962306a36Sopenharmony_ci		| (raw.ver_blank_start >> (8 - 3) & 0x08)
5062306a36Sopenharmony_ci		| (raw.ver_total >> (9 - 5) & 0x20)
5162306a36Sopenharmony_ci		| (raw.ver_addr >> (9 - 6) & 0x40)
5262306a36Sopenharmony_ci		| (raw.ver_sync_start >> (9 - 7) & 0x80), 0xEF);
5362306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x09, raw.ver_blank_start >> (9 - 5) & 0x20,
5462306a36Sopenharmony_ci		0x20);
5562306a36Sopenharmony_ci	via_write_reg(VIACR, 0x10, raw.ver_sync_start & 0xFF);
5662306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x11, raw.ver_sync_end & 0x0F, 0x0F);
5762306a36Sopenharmony_ci	via_write_reg(VIACR, 0x12, raw.ver_addr & 0xFF);
5862306a36Sopenharmony_ci	via_write_reg(VIACR, 0x15, raw.ver_blank_start & 0xFF);
5962306a36Sopenharmony_ci	via_write_reg(VIACR, 0x16, raw.ver_blank_end & 0xFF);
6062306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x33, (raw.hor_sync_start >> (8 - 4) & 0x10)
6162306a36Sopenharmony_ci		| (raw.hor_blank_end >> (6 - 5) & 0x20), 0x30);
6262306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x35, (raw.ver_total >> 10 & 0x01)
6362306a36Sopenharmony_ci		| (raw.ver_sync_start >> (10 - 1) & 0x02)
6462306a36Sopenharmony_ci		| (raw.ver_addr >> (10 - 2) & 0x04)
6562306a36Sopenharmony_ci		| (raw.ver_blank_start >> (10 - 3) & 0x08), 0x0F);
6662306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x36, raw.hor_total >> (8 - 3) & 0x08, 0x08);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* lock timing registers */
6962306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x11, 0x80, 0x80);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* reset timing control */
7262306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x17, 0x00, 0x80);
7362306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x17, 0x80, 0x80);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_civoid via_set_secondary_timing(const struct via_display_timing *timing)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct via_display_timing raw;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	raw.hor_total = timing->hor_total - 1;
8162306a36Sopenharmony_ci	raw.hor_addr = timing->hor_addr - 1;
8262306a36Sopenharmony_ci	raw.hor_blank_start = timing->hor_blank_start - 1;
8362306a36Sopenharmony_ci	raw.hor_blank_end = timing->hor_blank_end - 1;
8462306a36Sopenharmony_ci	raw.hor_sync_start = timing->hor_sync_start - 1;
8562306a36Sopenharmony_ci	raw.hor_sync_end = timing->hor_sync_end - 1;
8662306a36Sopenharmony_ci	raw.ver_total = timing->ver_total - 1;
8762306a36Sopenharmony_ci	raw.ver_addr = timing->ver_addr - 1;
8862306a36Sopenharmony_ci	raw.ver_blank_start = timing->ver_blank_start - 1;
8962306a36Sopenharmony_ci	raw.ver_blank_end = timing->ver_blank_end - 1;
9062306a36Sopenharmony_ci	raw.ver_sync_start = timing->ver_sync_start - 1;
9162306a36Sopenharmony_ci	raw.ver_sync_end = timing->ver_sync_end - 1;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	via_write_reg(VIACR, 0x50, raw.hor_total & 0xFF);
9462306a36Sopenharmony_ci	via_write_reg(VIACR, 0x51, raw.hor_addr & 0xFF);
9562306a36Sopenharmony_ci	via_write_reg(VIACR, 0x52, raw.hor_blank_start & 0xFF);
9662306a36Sopenharmony_ci	via_write_reg(VIACR, 0x53, raw.hor_blank_end & 0xFF);
9762306a36Sopenharmony_ci	via_write_reg(VIACR, 0x54, (raw.hor_blank_start >> 8 & 0x07)
9862306a36Sopenharmony_ci		| (raw.hor_blank_end >> (8 - 3) & 0x38)
9962306a36Sopenharmony_ci		| (raw.hor_sync_start >> (8 - 6) & 0xC0));
10062306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x55, (raw.hor_total >> 8 & 0x0F)
10162306a36Sopenharmony_ci		| (raw.hor_addr >> (8 - 4) & 0x70), 0x7F);
10262306a36Sopenharmony_ci	via_write_reg(VIACR, 0x56, raw.hor_sync_start & 0xFF);
10362306a36Sopenharmony_ci	via_write_reg(VIACR, 0x57, raw.hor_sync_end & 0xFF);
10462306a36Sopenharmony_ci	via_write_reg(VIACR, 0x58, raw.ver_total & 0xFF);
10562306a36Sopenharmony_ci	via_write_reg(VIACR, 0x59, raw.ver_addr & 0xFF);
10662306a36Sopenharmony_ci	via_write_reg(VIACR, 0x5A, raw.ver_blank_start & 0xFF);
10762306a36Sopenharmony_ci	via_write_reg(VIACR, 0x5B, raw.ver_blank_end & 0xFF);
10862306a36Sopenharmony_ci	via_write_reg(VIACR, 0x5C, (raw.ver_blank_start >> 8 & 0x07)
10962306a36Sopenharmony_ci		| (raw.ver_blank_end >> (8 - 3) & 0x38)
11062306a36Sopenharmony_ci		| (raw.hor_sync_end >> (8 - 6) & 0x40)
11162306a36Sopenharmony_ci		| (raw.hor_sync_start >> (10 - 7) & 0x80));
11262306a36Sopenharmony_ci	via_write_reg(VIACR, 0x5D, (raw.ver_total >> 8 & 0x07)
11362306a36Sopenharmony_ci		| (raw.ver_addr >> (8 - 3) & 0x38)
11462306a36Sopenharmony_ci		| (raw.hor_blank_end >> (11 - 6) & 0x40)
11562306a36Sopenharmony_ci		| (raw.hor_sync_start >> (11 - 7) & 0x80));
11662306a36Sopenharmony_ci	via_write_reg(VIACR, 0x5E, raw.ver_sync_start & 0xFF);
11762306a36Sopenharmony_ci	via_write_reg(VIACR, 0x5F, (raw.ver_sync_end & 0x1F)
11862306a36Sopenharmony_ci		| (raw.ver_sync_start >> (8 - 5) & 0xE0));
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_civoid via_set_primary_address(u32 addr)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr);
12462306a36Sopenharmony_ci	via_write_reg(VIACR, 0x0D, addr & 0xFF);
12562306a36Sopenharmony_ci	via_write_reg(VIACR, 0x0C, (addr >> 8) & 0xFF);
12662306a36Sopenharmony_ci	via_write_reg(VIACR, 0x34, (addr >> 16) & 0xFF);
12762306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x48, (addr >> 24) & 0x1F, 0x1F);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_civoid via_set_secondary_address(u32 addr)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "via_set_secondary_address(0x%08X)\n", addr);
13362306a36Sopenharmony_ci	/* secondary display supports only quadword aligned memory */
13462306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x62, (addr >> 2) & 0xFE, 0xFE);
13562306a36Sopenharmony_ci	via_write_reg(VIACR, 0x63, (addr >> 10) & 0xFF);
13662306a36Sopenharmony_ci	via_write_reg(VIACR, 0x64, (addr >> 18) & 0xFF);
13762306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0xA3, (addr >> 26) & 0x07, 0x07);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_civoid via_set_primary_pitch(u32 pitch)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "via_set_primary_pitch(0x%08X)\n", pitch);
14362306a36Sopenharmony_ci	/* spec does not say that first adapter skips 3 bits but old
14462306a36Sopenharmony_ci	 * code did it and seems to be reasonable in analogy to 2nd adapter
14562306a36Sopenharmony_ci	 */
14662306a36Sopenharmony_ci	pitch = pitch >> 3;
14762306a36Sopenharmony_ci	via_write_reg(VIACR, 0x13, pitch & 0xFF);
14862306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x35, (pitch >> (8 - 5)) & 0xE0, 0xE0);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_civoid via_set_secondary_pitch(u32 pitch)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n", pitch);
15462306a36Sopenharmony_ci	pitch = pitch >> 3;
15562306a36Sopenharmony_ci	via_write_reg(VIACR, 0x66, pitch & 0xFF);
15662306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x67, (pitch >> 8) & 0x03, 0x03);
15762306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x71, (pitch >> (10 - 7)) & 0x80, 0x80);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_civoid via_set_primary_color_depth(u8 depth)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	u8 value;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n", depth);
16562306a36Sopenharmony_ci	switch (depth) {
16662306a36Sopenharmony_ci	case 8:
16762306a36Sopenharmony_ci		value = 0x00;
16862306a36Sopenharmony_ci		break;
16962306a36Sopenharmony_ci	case 15:
17062306a36Sopenharmony_ci		value = 0x04;
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci	case 16:
17362306a36Sopenharmony_ci		value = 0x14;
17462306a36Sopenharmony_ci		break;
17562306a36Sopenharmony_ci	case 24:
17662306a36Sopenharmony_ci		value = 0x0C;
17762306a36Sopenharmony_ci		break;
17862306a36Sopenharmony_ci	case 30:
17962306a36Sopenharmony_ci		value = 0x08;
18062306a36Sopenharmony_ci		break;
18162306a36Sopenharmony_ci	default:
18262306a36Sopenharmony_ci		printk(KERN_WARNING "via_set_primary_color_depth: "
18362306a36Sopenharmony_ci			"Unsupported depth: %d\n", depth);
18462306a36Sopenharmony_ci		return;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	via_write_reg_mask(VIASR, 0x15, value, 0x1C);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_civoid via_set_secondary_color_depth(u8 depth)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	u8 value;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n", depth);
19562306a36Sopenharmony_ci	switch (depth) {
19662306a36Sopenharmony_ci	case 8:
19762306a36Sopenharmony_ci		value = 0x00;
19862306a36Sopenharmony_ci		break;
19962306a36Sopenharmony_ci	case 16:
20062306a36Sopenharmony_ci		value = 0x40;
20162306a36Sopenharmony_ci		break;
20262306a36Sopenharmony_ci	case 24:
20362306a36Sopenharmony_ci		value = 0xC0;
20462306a36Sopenharmony_ci		break;
20562306a36Sopenharmony_ci	case 30:
20662306a36Sopenharmony_ci		value = 0x80;
20762306a36Sopenharmony_ci		break;
20862306a36Sopenharmony_ci	default:
20962306a36Sopenharmony_ci		printk(KERN_WARNING "via_set_secondary_color_depth: "
21062306a36Sopenharmony_ci			"Unsupported depth: %d\n", depth);
21162306a36Sopenharmony_ci		return;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	via_write_reg_mask(VIACR, 0x67, value, 0xC0);
21562306a36Sopenharmony_ci}
216