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