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
18void 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
76void 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
121void 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
130void 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
140void 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
151void 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
160void 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
190void 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

source code of linux/drivers/video/fbdev/via/via_modesetting.c