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 | * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> |
6 | */ |
7 | /* |
8 | * basic modesetting functions |
9 | */ |
10 | |
11 | #include <linux/kernel.h> |
12 | #include <linux/via-core.h> |
13 | #include "via_modesetting.h" |
14 | #include "share.h" |
15 | #include "debug.h" |
16 | |
17 | |
18 | void via_set_primary_timing(const struct via_display_timing *timing) |
19 | { |
20 | struct via_display_timing raw; |
21 | |
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; |
34 | |
35 | /* unlock timing registers */ |
36 | via_write_reg_mask(VIACR, index: 0x11, data: 0x00, mask: 0x80); |
37 | |
38 | via_write_reg(VIACR, index: 0x00, data: raw.hor_total & 0xFF); |
39 | via_write_reg(VIACR, index: 0x01, data: raw.hor_addr & 0xFF); |
40 | via_write_reg(VIACR, index: 0x02, data: raw.hor_blank_start & 0xFF); |
41 | via_write_reg_mask(VIACR, index: 0x03, data: raw.hor_blank_end & 0x1F, mask: 0x1F); |
42 | via_write_reg(VIACR, index: 0x04, data: raw.hor_sync_start & 0xFF); |
43 | via_write_reg_mask(VIACR, index: 0x05, data: (raw.hor_sync_end & 0x1F) |
44 | | (raw.hor_blank_end << (7 - 5) & 0x80), mask: 0x9F); |
45 | via_write_reg(VIACR, index: 0x06, data: raw.ver_total & 0xFF); |
46 | via_write_reg_mask(VIACR, index: 0x07, data: (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), mask: 0xEF); |
53 | via_write_reg_mask(VIACR, index: 0x09, data: raw.ver_blank_start >> (9 - 5) & 0x20, |
54 | mask: 0x20); |
55 | via_write_reg(VIACR, index: 0x10, data: raw.ver_sync_start & 0xFF); |
56 | via_write_reg_mask(VIACR, index: 0x11, data: raw.ver_sync_end & 0x0F, mask: 0x0F); |
57 | via_write_reg(VIACR, index: 0x12, data: raw.ver_addr & 0xFF); |
58 | via_write_reg(VIACR, index: 0x15, data: raw.ver_blank_start & 0xFF); |
59 | via_write_reg(VIACR, index: 0x16, data: raw.ver_blank_end & 0xFF); |
60 | via_write_reg_mask(VIACR, index: 0x33, data: (raw.hor_sync_start >> (8 - 4) & 0x10) |
61 | | (raw.hor_blank_end >> (6 - 5) & 0x20), mask: 0x30); |
62 | via_write_reg_mask(VIACR, index: 0x35, data: (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), mask: 0x0F); |
66 | via_write_reg_mask(VIACR, index: 0x36, data: raw.hor_total >> (8 - 3) & 0x08, mask: 0x08); |
67 | |
68 | /* lock timing registers */ |
69 | via_write_reg_mask(VIACR, index: 0x11, data: 0x80, mask: 0x80); |
70 | |
71 | /* reset timing control */ |
72 | via_write_reg_mask(VIACR, index: 0x17, data: 0x00, mask: 0x80); |
73 | via_write_reg_mask(VIACR, index: 0x17, data: 0x80, mask: 0x80); |
74 | } |
75 | |
76 | void via_set_secondary_timing(const struct via_display_timing *timing) |
77 | { |
78 | struct via_display_timing raw; |
79 | |
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; |
92 | |
93 | via_write_reg(VIACR, index: 0x50, data: raw.hor_total & 0xFF); |
94 | via_write_reg(VIACR, index: 0x51, data: raw.hor_addr & 0xFF); |
95 | via_write_reg(VIACR, index: 0x52, data: raw.hor_blank_start & 0xFF); |
96 | via_write_reg(VIACR, index: 0x53, data: raw.hor_blank_end & 0xFF); |
97 | via_write_reg(VIACR, index: 0x54, data: (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, index: 0x55, data: (raw.hor_total >> 8 & 0x0F) |
101 | | (raw.hor_addr >> (8 - 4) & 0x70), mask: 0x7F); |
102 | via_write_reg(VIACR, index: 0x56, data: raw.hor_sync_start & 0xFF); |
103 | via_write_reg(VIACR, index: 0x57, data: raw.hor_sync_end & 0xFF); |
104 | via_write_reg(VIACR, index: 0x58, data: raw.ver_total & 0xFF); |
105 | via_write_reg(VIACR, index: 0x59, data: raw.ver_addr & 0xFF); |
106 | via_write_reg(VIACR, index: 0x5A, data: raw.ver_blank_start & 0xFF); |
107 | via_write_reg(VIACR, index: 0x5B, data: raw.ver_blank_end & 0xFF); |
108 | via_write_reg(VIACR, index: 0x5C, data: (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, index: 0x5D, data: (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, index: 0x5E, data: raw.ver_sync_start & 0xFF); |
117 | via_write_reg(VIACR, index: 0x5F, data: (raw.ver_sync_end & 0x1F) |
118 | | (raw.ver_sync_start >> (8 - 5) & 0xE0)); |
119 | } |
120 | |
121 | void via_set_primary_address(u32 addr) |
122 | { |
123 | DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n" , addr); |
124 | via_write_reg(VIACR, index: 0x0D, data: addr & 0xFF); |
125 | via_write_reg(VIACR, index: 0x0C, data: (addr >> 8) & 0xFF); |
126 | via_write_reg(VIACR, index: 0x34, data: (addr >> 16) & 0xFF); |
127 | via_write_reg_mask(VIACR, index: 0x48, data: (addr >> 24) & 0x1F, mask: 0x1F); |
128 | } |
129 | |
130 | void via_set_secondary_address(u32 addr) |
131 | { |
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, index: 0x62, data: (addr >> 2) & 0xFE, mask: 0xFE); |
135 | via_write_reg(VIACR, index: 0x63, data: (addr >> 10) & 0xFF); |
136 | via_write_reg(VIACR, index: 0x64, data: (addr >> 18) & 0xFF); |
137 | via_write_reg_mask(VIACR, index: 0xA3, data: (addr >> 26) & 0x07, mask: 0x07); |
138 | } |
139 | |
140 | void via_set_primary_pitch(u32 pitch) |
141 | { |
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 |
145 | */ |
146 | pitch = pitch >> 3; |
147 | via_write_reg(VIACR, index: 0x13, data: pitch & 0xFF); |
148 | via_write_reg_mask(VIACR, index: 0x35, data: (pitch >> (8 - 5)) & 0xE0, mask: 0xE0); |
149 | } |
150 | |
151 | void via_set_secondary_pitch(u32 pitch) |
152 | { |
153 | DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n" , pitch); |
154 | pitch = pitch >> 3; |
155 | via_write_reg(VIACR, index: 0x66, data: pitch & 0xFF); |
156 | via_write_reg_mask(VIACR, index: 0x67, data: (pitch >> 8) & 0x03, mask: 0x03); |
157 | via_write_reg_mask(VIACR, index: 0x71, data: (pitch >> (10 - 7)) & 0x80, mask: 0x80); |
158 | } |
159 | |
160 | void via_set_primary_color_depth(u8 depth) |
161 | { |
162 | u8 value; |
163 | |
164 | DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n" , depth); |
165 | switch (depth) { |
166 | case 8: |
167 | value = 0x00; |
168 | break; |
169 | case 15: |
170 | value = 0x04; |
171 | break; |
172 | case 16: |
173 | value = 0x14; |
174 | break; |
175 | case 24: |
176 | value = 0x0C; |
177 | break; |
178 | case 30: |
179 | value = 0x08; |
180 | break; |
181 | default: |
182 | printk(KERN_WARNING "via_set_primary_color_depth: " |
183 | "Unsupported depth: %d\n" , depth); |
184 | return; |
185 | } |
186 | |
187 | via_write_reg_mask(VIASR, index: 0x15, data: value, mask: 0x1C); |
188 | } |
189 | |
190 | void via_set_secondary_color_depth(u8 depth) |
191 | { |
192 | u8 value; |
193 | |
194 | DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n" , depth); |
195 | switch (depth) { |
196 | case 8: |
197 | value = 0x00; |
198 | break; |
199 | case 16: |
200 | value = 0x40; |
201 | break; |
202 | case 24: |
203 | value = 0xC0; |
204 | break; |
205 | case 30: |
206 | value = 0x80; |
207 | break; |
208 | default: |
209 | printk(KERN_WARNING "via_set_secondary_color_depth: " |
210 | "Unsupported depth: %d\n" , depth); |
211 | return; |
212 | } |
213 | |
214 | via_write_reg_mask(VIACR, index: 0x67, data: value, mask: 0xC0); |
215 | } |
216 | |