1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
4 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
5 * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
8 * basic modesetting functions
11 #include <linux/kernel.h>
12 #include <linux/via-core.h>
13 #include "via_modesetting.h"
18 void via_set_primary_timing(const struct via_display_timing
*timing
)
20 struct via_display_timing raw
;
22 raw
.hor_total
= timing
->hor_total
/ 8 - 5;
23 raw
.hor_addr
= timing
->hor_addr
/ 8 - 1;
24 raw
.hor_blank_start
= timing
->hor_blank_start
/ 8 - 1;
25 raw
.hor_blank_end
= timing
->hor_blank_end
/ 8 - 1;
26 raw
.hor_sync_start
= timing
->hor_sync_start
/ 8;
27 raw
.hor_sync_end
= timing
->hor_sync_end
/ 8;
28 raw
.ver_total
= timing
->ver_total
- 2;
29 raw
.ver_addr
= timing
->ver_addr
- 1;
30 raw
.ver_blank_start
= timing
->ver_blank_start
- 1;
31 raw
.ver_blank_end
= timing
->ver_blank_end
- 1;
32 raw
.ver_sync_start
= timing
->ver_sync_start
- 1;
33 raw
.ver_sync_end
= timing
->ver_sync_end
- 1;
35 /* unlock timing registers */
36 via_write_reg_mask(VIACR
, 0x11, 0x00, 0x80);
38 via_write_reg(VIACR
, 0x00, raw
.hor_total
& 0xFF);
39 via_write_reg(VIACR
, 0x01, raw
.hor_addr
& 0xFF);
40 via_write_reg(VIACR
, 0x02, raw
.hor_blank_start
& 0xFF);
41 via_write_reg_mask(VIACR
, 0x03, raw
.hor_blank_end
& 0x1F, 0x1F);
42 via_write_reg(VIACR
, 0x04, raw
.hor_sync_start
& 0xFF);
43 via_write_reg_mask(VIACR
, 0x05, (raw
.hor_sync_end
& 0x1F)
44 | (raw
.hor_blank_end
<< (7 - 5) & 0x80), 0x9F);
45 via_write_reg(VIACR
, 0x06, raw
.ver_total
& 0xFF);
46 via_write_reg_mask(VIACR
, 0x07, (raw
.ver_total
>> 8 & 0x01)
47 | (raw
.ver_addr
>> (8 - 1) & 0x02)
48 | (raw
.ver_sync_start
>> (8 - 2) & 0x04)
49 | (raw
.ver_blank_start
>> (8 - 3) & 0x08)
50 | (raw
.ver_total
>> (9 - 5) & 0x20)
51 | (raw
.ver_addr
>> (9 - 6) & 0x40)
52 | (raw
.ver_sync_start
>> (9 - 7) & 0x80), 0xEF);
53 via_write_reg_mask(VIACR
, 0x09, raw
.ver_blank_start
>> (9 - 5) & 0x20,
55 via_write_reg(VIACR
, 0x10, raw
.ver_sync_start
& 0xFF);
56 via_write_reg_mask(VIACR
, 0x11, raw
.ver_sync_end
& 0x0F, 0x0F);
57 via_write_reg(VIACR
, 0x12, raw
.ver_addr
& 0xFF);
58 via_write_reg(VIACR
, 0x15, raw
.ver_blank_start
& 0xFF);
59 via_write_reg(VIACR
, 0x16, raw
.ver_blank_end
& 0xFF);
60 via_write_reg_mask(VIACR
, 0x33, (raw
.hor_sync_start
>> (8 - 4) & 0x10)
61 | (raw
.hor_blank_end
>> (6 - 5) & 0x20), 0x30);
62 via_write_reg_mask(VIACR
, 0x35, (raw
.ver_total
>> 10 & 0x01)
63 | (raw
.ver_sync_start
>> (10 - 1) & 0x02)
64 | (raw
.ver_addr
>> (10 - 2) & 0x04)
65 | (raw
.ver_blank_start
>> (10 - 3) & 0x08), 0x0F);
66 via_write_reg_mask(VIACR
, 0x36, raw
.hor_total
>> (8 - 3) & 0x08, 0x08);
68 /* lock timing registers */
69 via_write_reg_mask(VIACR
, 0x11, 0x80, 0x80);
71 /* reset timing control */
72 via_write_reg_mask(VIACR
, 0x17, 0x00, 0x80);
73 via_write_reg_mask(VIACR
, 0x17, 0x80, 0x80);
76 void via_set_secondary_timing(const struct via_display_timing
*timing
)
78 struct via_display_timing raw
;
80 raw
.hor_total
= timing
->hor_total
- 1;
81 raw
.hor_addr
= timing
->hor_addr
- 1;
82 raw
.hor_blank_start
= timing
->hor_blank_start
- 1;
83 raw
.hor_blank_end
= timing
->hor_blank_end
- 1;
84 raw
.hor_sync_start
= timing
->hor_sync_start
- 1;
85 raw
.hor_sync_end
= timing
->hor_sync_end
- 1;
86 raw
.ver_total
= timing
->ver_total
- 1;
87 raw
.ver_addr
= timing
->ver_addr
- 1;
88 raw
.ver_blank_start
= timing
->ver_blank_start
- 1;
89 raw
.ver_blank_end
= timing
->ver_blank_end
- 1;
90 raw
.ver_sync_start
= timing
->ver_sync_start
- 1;
91 raw
.ver_sync_end
= timing
->ver_sync_end
- 1;
93 via_write_reg(VIACR
, 0x50, raw
.hor_total
& 0xFF);
94 via_write_reg(VIACR
, 0x51, raw
.hor_addr
& 0xFF);
95 via_write_reg(VIACR
, 0x52, raw
.hor_blank_start
& 0xFF);
96 via_write_reg(VIACR
, 0x53, raw
.hor_blank_end
& 0xFF);
97 via_write_reg(VIACR
, 0x54, (raw
.hor_blank_start
>> 8 & 0x07)
98 | (raw
.hor_blank_end
>> (8 - 3) & 0x38)
99 | (raw
.hor_sync_start
>> (8 - 6) & 0xC0));
100 via_write_reg_mask(VIACR
, 0x55, (raw
.hor_total
>> 8 & 0x0F)
101 | (raw
.hor_addr
>> (8 - 4) & 0x70), 0x7F);
102 via_write_reg(VIACR
, 0x56, raw
.hor_sync_start
& 0xFF);
103 via_write_reg(VIACR
, 0x57, raw
.hor_sync_end
& 0xFF);
104 via_write_reg(VIACR
, 0x58, raw
.ver_total
& 0xFF);
105 via_write_reg(VIACR
, 0x59, raw
.ver_addr
& 0xFF);
106 via_write_reg(VIACR
, 0x5A, raw
.ver_blank_start
& 0xFF);
107 via_write_reg(VIACR
, 0x5B, raw
.ver_blank_end
& 0xFF);
108 via_write_reg(VIACR
, 0x5C, (raw
.ver_blank_start
>> 8 & 0x07)
109 | (raw
.ver_blank_end
>> (8 - 3) & 0x38)
110 | (raw
.hor_sync_end
>> (8 - 6) & 0x40)
111 | (raw
.hor_sync_start
>> (10 - 7) & 0x80));
112 via_write_reg(VIACR
, 0x5D, (raw
.ver_total
>> 8 & 0x07)
113 | (raw
.ver_addr
>> (8 - 3) & 0x38)
114 | (raw
.hor_blank_end
>> (11 - 6) & 0x40)
115 | (raw
.hor_sync_start
>> (11 - 7) & 0x80));
116 via_write_reg(VIACR
, 0x5E, raw
.ver_sync_start
& 0xFF);
117 via_write_reg(VIACR
, 0x5F, (raw
.ver_sync_end
& 0x1F)
118 | (raw
.ver_sync_start
>> (8 - 5) & 0xE0));
121 void via_set_primary_address(u32 addr
)
123 DEBUG_MSG(KERN_DEBUG
"via_set_primary_address(0x%08X)\n", addr
);
124 via_write_reg(VIACR
, 0x0D, addr
& 0xFF);
125 via_write_reg(VIACR
, 0x0C, (addr
>> 8) & 0xFF);
126 via_write_reg(VIACR
, 0x34, (addr
>> 16) & 0xFF);
127 via_write_reg_mask(VIACR
, 0x48, (addr
>> 24) & 0x1F, 0x1F);
130 void via_set_secondary_address(u32 addr
)
132 DEBUG_MSG(KERN_DEBUG
"via_set_secondary_address(0x%08X)\n", addr
);
133 /* secondary display supports only quadword aligned memory */
134 via_write_reg_mask(VIACR
, 0x62, (addr
>> 2) & 0xFE, 0xFE);
135 via_write_reg(VIACR
, 0x63, (addr
>> 10) & 0xFF);
136 via_write_reg(VIACR
, 0x64, (addr
>> 18) & 0xFF);
137 via_write_reg_mask(VIACR
, 0xA3, (addr
>> 26) & 0x07, 0x07);
140 void via_set_primary_pitch(u32 pitch
)
142 DEBUG_MSG(KERN_DEBUG
"via_set_primary_pitch(0x%08X)\n", pitch
);
143 /* spec does not say that first adapter skips 3 bits but old
144 * code did it and seems to be reasonable in analogy to 2nd adapter
147 via_write_reg(VIACR
, 0x13, pitch
& 0xFF);
148 via_write_reg_mask(VIACR
, 0x35, (pitch
>> (8 - 5)) & 0xE0, 0xE0);
151 void via_set_secondary_pitch(u32 pitch
)
153 DEBUG_MSG(KERN_DEBUG
"via_set_secondary_pitch(0x%08X)\n", pitch
);
155 via_write_reg(VIACR
, 0x66, pitch
& 0xFF);
156 via_write_reg_mask(VIACR
, 0x67, (pitch
>> 8) & 0x03, 0x03);
157 via_write_reg_mask(VIACR
, 0x71, (pitch
>> (10 - 7)) & 0x80, 0x80);
160 void via_set_primary_color_depth(u8 depth
)
164 DEBUG_MSG(KERN_DEBUG
"via_set_primary_color_depth(%d)\n", depth
);
182 printk(KERN_WARNING
"via_set_primary_color_depth: "
183 "Unsupported depth: %d\n", depth
);
187 via_write_reg_mask(VIASR
, 0x15, value
, 0x1C);
190 void via_set_secondary_color_depth(u8 depth
)
194 DEBUG_MSG(KERN_DEBUG
"via_set_secondary_color_depth(%d)\n", depth
);
209 printk(KERN_WARNING
"via_set_secondary_color_depth: "
210 "Unsupported depth: %d\n", depth
);
214 via_write_reg_mask(VIACR
, 0x67, value
, 0xC0);