18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. 48c2ecf20Sopenharmony_ci * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci/* 88c2ecf20Sopenharmony_ci * basic modesetting functions 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/via-core.h> 138c2ecf20Sopenharmony_ci#include "via_modesetting.h" 148c2ecf20Sopenharmony_ci#include "share.h" 158c2ecf20Sopenharmony_ci#include "debug.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_civoid via_set_primary_timing(const struct via_display_timing *timing) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci struct via_display_timing raw; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci raw.hor_total = timing->hor_total / 8 - 5; 238c2ecf20Sopenharmony_ci raw.hor_addr = timing->hor_addr / 8 - 1; 248c2ecf20Sopenharmony_ci raw.hor_blank_start = timing->hor_blank_start / 8 - 1; 258c2ecf20Sopenharmony_ci raw.hor_blank_end = timing->hor_blank_end / 8 - 1; 268c2ecf20Sopenharmony_ci raw.hor_sync_start = timing->hor_sync_start / 8; 278c2ecf20Sopenharmony_ci raw.hor_sync_end = timing->hor_sync_end / 8; 288c2ecf20Sopenharmony_ci raw.ver_total = timing->ver_total - 2; 298c2ecf20Sopenharmony_ci raw.ver_addr = timing->ver_addr - 1; 308c2ecf20Sopenharmony_ci raw.ver_blank_start = timing->ver_blank_start - 1; 318c2ecf20Sopenharmony_ci raw.ver_blank_end = timing->ver_blank_end - 1; 328c2ecf20Sopenharmony_ci raw.ver_sync_start = timing->ver_sync_start - 1; 338c2ecf20Sopenharmony_ci raw.ver_sync_end = timing->ver_sync_end - 1; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* unlock timing registers */ 368c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x11, 0x00, 0x80); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x00, raw.hor_total & 0xFF); 398c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x01, raw.hor_addr & 0xFF); 408c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x02, raw.hor_blank_start & 0xFF); 418c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x03, raw.hor_blank_end & 0x1F, 0x1F); 428c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x04, raw.hor_sync_start & 0xFF); 438c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x05, (raw.hor_sync_end & 0x1F) 448c2ecf20Sopenharmony_ci | (raw.hor_blank_end << (7 - 5) & 0x80), 0x9F); 458c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x06, raw.ver_total & 0xFF); 468c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x07, (raw.ver_total >> 8 & 0x01) 478c2ecf20Sopenharmony_ci | (raw.ver_addr >> (8 - 1) & 0x02) 488c2ecf20Sopenharmony_ci | (raw.ver_sync_start >> (8 - 2) & 0x04) 498c2ecf20Sopenharmony_ci | (raw.ver_blank_start >> (8 - 3) & 0x08) 508c2ecf20Sopenharmony_ci | (raw.ver_total >> (9 - 5) & 0x20) 518c2ecf20Sopenharmony_ci | (raw.ver_addr >> (9 - 6) & 0x40) 528c2ecf20Sopenharmony_ci | (raw.ver_sync_start >> (9 - 7) & 0x80), 0xEF); 538c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x09, raw.ver_blank_start >> (9 - 5) & 0x20, 548c2ecf20Sopenharmony_ci 0x20); 558c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x10, raw.ver_sync_start & 0xFF); 568c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x11, raw.ver_sync_end & 0x0F, 0x0F); 578c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x12, raw.ver_addr & 0xFF); 588c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x15, raw.ver_blank_start & 0xFF); 598c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x16, raw.ver_blank_end & 0xFF); 608c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x33, (raw.hor_sync_start >> (8 - 4) & 0x10) 618c2ecf20Sopenharmony_ci | (raw.hor_blank_end >> (6 - 5) & 0x20), 0x30); 628c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x35, (raw.ver_total >> 10 & 0x01) 638c2ecf20Sopenharmony_ci | (raw.ver_sync_start >> (10 - 1) & 0x02) 648c2ecf20Sopenharmony_ci | (raw.ver_addr >> (10 - 2) & 0x04) 658c2ecf20Sopenharmony_ci | (raw.ver_blank_start >> (10 - 3) & 0x08), 0x0F); 668c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x36, raw.hor_total >> (8 - 3) & 0x08, 0x08); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* lock timing registers */ 698c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x11, 0x80, 0x80); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* reset timing control */ 728c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x17, 0x00, 0x80); 738c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x17, 0x80, 0x80); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_civoid via_set_secondary_timing(const struct via_display_timing *timing) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct via_display_timing raw; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci raw.hor_total = timing->hor_total - 1; 818c2ecf20Sopenharmony_ci raw.hor_addr = timing->hor_addr - 1; 828c2ecf20Sopenharmony_ci raw.hor_blank_start = timing->hor_blank_start - 1; 838c2ecf20Sopenharmony_ci raw.hor_blank_end = timing->hor_blank_end - 1; 848c2ecf20Sopenharmony_ci raw.hor_sync_start = timing->hor_sync_start - 1; 858c2ecf20Sopenharmony_ci raw.hor_sync_end = timing->hor_sync_end - 1; 868c2ecf20Sopenharmony_ci raw.ver_total = timing->ver_total - 1; 878c2ecf20Sopenharmony_ci raw.ver_addr = timing->ver_addr - 1; 888c2ecf20Sopenharmony_ci raw.ver_blank_start = timing->ver_blank_start - 1; 898c2ecf20Sopenharmony_ci raw.ver_blank_end = timing->ver_blank_end - 1; 908c2ecf20Sopenharmony_ci raw.ver_sync_start = timing->ver_sync_start - 1; 918c2ecf20Sopenharmony_ci raw.ver_sync_end = timing->ver_sync_end - 1; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x50, raw.hor_total & 0xFF); 948c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x51, raw.hor_addr & 0xFF); 958c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x52, raw.hor_blank_start & 0xFF); 968c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x53, raw.hor_blank_end & 0xFF); 978c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x54, (raw.hor_blank_start >> 8 & 0x07) 988c2ecf20Sopenharmony_ci | (raw.hor_blank_end >> (8 - 3) & 0x38) 998c2ecf20Sopenharmony_ci | (raw.hor_sync_start >> (8 - 6) & 0xC0)); 1008c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x55, (raw.hor_total >> 8 & 0x0F) 1018c2ecf20Sopenharmony_ci | (raw.hor_addr >> (8 - 4) & 0x70), 0x7F); 1028c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x56, raw.hor_sync_start & 0xFF); 1038c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x57, raw.hor_sync_end & 0xFF); 1048c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x58, raw.ver_total & 0xFF); 1058c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x59, raw.ver_addr & 0xFF); 1068c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x5A, raw.ver_blank_start & 0xFF); 1078c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x5B, raw.ver_blank_end & 0xFF); 1088c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x5C, (raw.ver_blank_start >> 8 & 0x07) 1098c2ecf20Sopenharmony_ci | (raw.ver_blank_end >> (8 - 3) & 0x38) 1108c2ecf20Sopenharmony_ci | (raw.hor_sync_end >> (8 - 6) & 0x40) 1118c2ecf20Sopenharmony_ci | (raw.hor_sync_start >> (10 - 7) & 0x80)); 1128c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x5D, (raw.ver_total >> 8 & 0x07) 1138c2ecf20Sopenharmony_ci | (raw.ver_addr >> (8 - 3) & 0x38) 1148c2ecf20Sopenharmony_ci | (raw.hor_blank_end >> (11 - 6) & 0x40) 1158c2ecf20Sopenharmony_ci | (raw.hor_sync_start >> (11 - 7) & 0x80)); 1168c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x5E, raw.ver_sync_start & 0xFF); 1178c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x5F, (raw.ver_sync_end & 0x1F) 1188c2ecf20Sopenharmony_ci | (raw.ver_sync_start >> (8 - 5) & 0xE0)); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_civoid via_set_primary_address(u32 addr) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr); 1248c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x0D, addr & 0xFF); 1258c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x0C, (addr >> 8) & 0xFF); 1268c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x34, (addr >> 16) & 0xFF); 1278c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x48, (addr >> 24) & 0x1F, 0x1F); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_civoid via_set_secondary_address(u32 addr) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci DEBUG_MSG(KERN_DEBUG "via_set_secondary_address(0x%08X)\n", addr); 1338c2ecf20Sopenharmony_ci /* secondary display supports only quadword aligned memory */ 1348c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x62, (addr >> 2) & 0xFE, 0xFE); 1358c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x63, (addr >> 10) & 0xFF); 1368c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x64, (addr >> 18) & 0xFF); 1378c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0xA3, (addr >> 26) & 0x07, 0x07); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_civoid via_set_primary_pitch(u32 pitch) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci DEBUG_MSG(KERN_DEBUG "via_set_primary_pitch(0x%08X)\n", pitch); 1438c2ecf20Sopenharmony_ci /* spec does not say that first adapter skips 3 bits but old 1448c2ecf20Sopenharmony_ci * code did it and seems to be reasonable in analogy to 2nd adapter 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ci pitch = pitch >> 3; 1478c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x13, pitch & 0xFF); 1488c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x35, (pitch >> (8 - 5)) & 0xE0, 0xE0); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_civoid via_set_secondary_pitch(u32 pitch) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n", pitch); 1548c2ecf20Sopenharmony_ci pitch = pitch >> 3; 1558c2ecf20Sopenharmony_ci via_write_reg(VIACR, 0x66, pitch & 0xFF); 1568c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x67, (pitch >> 8) & 0x03, 0x03); 1578c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x71, (pitch >> (10 - 7)) & 0x80, 0x80); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_civoid via_set_primary_color_depth(u8 depth) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci u8 value; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n", depth); 1658c2ecf20Sopenharmony_ci switch (depth) { 1668c2ecf20Sopenharmony_ci case 8: 1678c2ecf20Sopenharmony_ci value = 0x00; 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci case 15: 1708c2ecf20Sopenharmony_ci value = 0x04; 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci case 16: 1738c2ecf20Sopenharmony_ci value = 0x14; 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci case 24: 1768c2ecf20Sopenharmony_ci value = 0x0C; 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci case 30: 1798c2ecf20Sopenharmony_ci value = 0x08; 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci default: 1828c2ecf20Sopenharmony_ci printk(KERN_WARNING "via_set_primary_color_depth: " 1838c2ecf20Sopenharmony_ci "Unsupported depth: %d\n", depth); 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci via_write_reg_mask(VIASR, 0x15, value, 0x1C); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_civoid via_set_secondary_color_depth(u8 depth) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci u8 value; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n", depth); 1958c2ecf20Sopenharmony_ci switch (depth) { 1968c2ecf20Sopenharmony_ci case 8: 1978c2ecf20Sopenharmony_ci value = 0x00; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci case 16: 2008c2ecf20Sopenharmony_ci value = 0x40; 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci case 24: 2038c2ecf20Sopenharmony_ci value = 0xC0; 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci case 30: 2068c2ecf20Sopenharmony_ci value = 0x80; 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci default: 2098c2ecf20Sopenharmony_ci printk(KERN_WARNING "via_set_secondary_color_depth: " 2108c2ecf20Sopenharmony_ci "Unsupported depth: %d\n", depth); 2118c2ecf20Sopenharmony_ci return; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci via_write_reg_mask(VIACR, 0x67, value, 0xC0); 2158c2ecf20Sopenharmony_ci} 216