xref: /aosp_15_r20/external/coreboot/src/drivers/emulation/qemu/cirrus.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <stdint.h>
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/pci.h>
7 #include <device/pci_ops.h>
8 #include <pc80/vga.h>
9 #include <pc80/vga_io.h>
10 #include <framebuffer_info.h>
11 
12 static int width  = CONFIG_DRIVERS_EMULATION_QEMU_XRES;
13 static int height = CONFIG_DRIVERS_EMULATION_QEMU_YRES;
14 static u32 addr   = 0;
15 
16 enum
17   {
18     VGA_CR_HTOTAL = 0x00,
19     VGA_CR_HORIZ_END = 0x01,
20     VGA_CR_HBLANK_START = 0x02,
21     VGA_CR_HBLANK_END = 0x03,
22     VGA_CR_HORIZ_SYNC_PULSE_START = 0x04,
23     VGA_CR_HORIZ_SYNC_PULSE_END = 0x05,
24     VGA_CR_VERT_TOTAL = 0x06,
25     VGA_CR_OVERFLOW = 0x07,
26     VGA_CR_BYTE_PANNING = 0x08,
27     VGA_CR_CELL_HEIGHT = 0x09,
28     VGA_CR_CURSOR_START = 0x0a,
29     VGA_CR_CURSOR_END = 0x0b,
30     VGA_CR_START_ADDR_HIGH_REGISTER = 0x0c,
31     VGA_CR_START_ADDR_LOW_REGISTER = 0x0d,
32     VGA_CR_CURSOR_ADDR_HIGH = 0x0e,
33     VGA_CR_CURSOR_ADDR_LOW = 0x0f,
34     VGA_CR_VSYNC_START = 0x10,
35     VGA_CR_VSYNC_END = 0x11,
36     VGA_CR_VDISPLAY_END = 0x12,
37     VGA_CR_PITCH = 0x13,
38     VGA_CR_UNDERLINE_LOCATION = 0x14,
39     VGA_CR_VERTICAL_BLANK_START = 0x15,
40     VGA_CR_VERTICAL_BLANK_END = 0x16,
41     VGA_CR_MODE = 0x17,
42     VGA_CR_LINE_COMPARE = 0x18,
43   };
44 
45 #define VGA_IO_MISC_COLOR 0x01
46 
47 #define VGA_CR_WIDTH_DIVISOR 8
48 
49 #define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT 7
50 #define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK 0x02
51 #define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT 3
52 #define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK 0x40
53 
54 #define VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT 8
55 #define VGA_CR_OVERFLOW_VERT_TOTAL1_MASK 0x01
56 #define VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT 4
57 #define VGA_CR_OVERFLOW_VERT_TOTAL2_MASK 0x20
58 
59 #define VGA_CR_OVERFLOW_VSYNC_START1_SHIFT 6
60 #define VGA_CR_OVERFLOW_VSYNC_START1_MASK 0x04
61 #define VGA_CR_OVERFLOW_VSYNC_START2_SHIFT 2
62 #define VGA_CR_OVERFLOW_VSYNC_START2_MASK 0x80
63 
64 #define VGA_CR_OVERFLOW_HEIGHT1_SHIFT 7
65 #define VGA_CR_OVERFLOW_HEIGHT1_MASK 0x02
66 #define VGA_CR_OVERFLOW_HEIGHT2_SHIFT 3
67 #define VGA_CR_OVERFLOW_HEIGHT2_MASK 0xc0
68 #define VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT 4
69 #define VGA_CR_OVERFLOW_LINE_COMPARE_MASK 0x10
70 
71 #define VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK 0x40
72 #define VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT 3
73 #define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK 0x20
74 #define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT 4
75 #define VGA_CR_CELL_HEIGHT_DOUBLE_SCAN 0x80
76 enum
77   {
78     VGA_CR_CURSOR_START_DISABLE = (1 << 5)
79   };
80 
81 #define VGA_CR_PITCH_DIVISOR 8
82 
83 enum
84   {
85     VGA_CR_MODE_NO_CGA = 0x01,
86     VGA_CR_MODE_NO_HERCULES = 0x02,
87     VGA_CR_MODE_ADDRESS_WRAP = 0x20,
88     VGA_CR_MODE_BYTE_MODE = 0x40,
89     VGA_CR_MODE_TIMING_ENABLE = 0x80
90   };
91 
92 enum
93   {
94     VGA_SR_RESET = 0,
95     VGA_SR_CLOCKING_MODE = 1,
96     VGA_SR_MAP_MASK_REGISTER = 2,
97     VGA_SR_CHAR_MAP_SELECT = 3,
98     VGA_SR_MEMORY_MODE = 4,
99   };
100 
101 enum
102   {
103     VGA_SR_RESET_ASYNC = 1,
104     VGA_SR_RESET_SYNC = 2
105   };
106 
107 enum
108   {
109     VGA_SR_CLOCKING_MODE_8_DOT_CLOCK = 1
110   };
111 
112 enum
113   {
114     VGA_SR_MEMORY_MODE_NORMAL = 0,
115     VGA_SR_MEMORY_MODE_EXTERNAL_VIDEO_MEMORY = 2,
116     VGA_SR_MEMORY_MODE_SEQUENTIAL_ADDRESSING = 4,
117     VGA_SR_MEMORY_MODE_CHAIN4 = 8,
118   };
119 
120 enum
121   {
122     VGA_GR_SET_RESET_PLANE = 0,
123     VGA_GR_SET_RESET_PLANE_ENABLE = 1,
124     VGA_GR_COLOR_COMPARE = 2,
125     VGA_GR_READ_MAP_REGISTER = 4,
126     VGA_GR_MODE = 5,
127     VGA_GR_GR6 = 6,
128     VGA_GR_COLOR_COMPARE_DISABLE = 7,
129     VGA_GR_BITMASK = 8,
130     VGA_GR_MAX
131   };
132 
133 enum
134   {
135     VGA_TEXT_TEXT_PLANE = 0,
136     VGA_TEXT_ATTR_PLANE = 1,
137     VGA_TEXT_FONT_PLANE = 2
138   };
139 
140 enum
141   {
142     VGA_GR_GR6_GRAPHICS_MODE = 1,
143     VGA_GR_GR6_MMAP_A0 = (1 << 2),
144     VGA_GR_GR6_MMAP_CGA = (3 << 2)
145   };
146 
147 enum
148   {
149     VGA_GR_MODE_READ_MODE1 = 0x08,
150     VGA_GR_MODE_ODD_EVEN = 0x10,
151     VGA_GR_MODE_ODD_EVEN_SHIFT = 0x20,
152     VGA_GR_MODE_256_COLOR = 0x40
153   };
154 
155 #define CIRRUS_CR_EXTENDED_DISPLAY 0x1b
156 #define CIRRUS_CR_EXTENDED_OVERLAY 0x1d
157 
158 #define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK 0x10
159 #define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT 4
160 #define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK1 0x1
161 #define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT1 16
162 #define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK2 0xc
163 #define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT2 15
164 
165 #define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_MASK 0x80
166 #define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_SHIFT 12
167 #define CIRRUS_SR_EXTENDED_MODE 7
168 #define CIRRUS_SR_EXTENDED_MODE_LFB_ENABLE 0xf0
169 #define CIRRUS_SR_EXTENDED_MODE_ENABLE_EXT 0x01
170 #define CIRRUS_SR_EXTENDED_MODE_32BPP      0x08
171 #define CIRRUS_HIDDEN_DAC_888COLOR 0xc5
172 
173 static void
write_hidden_dac(uint8_t data)174 write_hidden_dac(uint8_t data)
175 {
176 	inb(0x3c8);
177 	inb(0x3c6);
178 	inb(0x3c6);
179 	inb(0x3c6);
180 	inb(0x3c6);
181 	outb(data, 0x3c6);
182 }
183 
cirrus_init_linear_fb(struct device * dev)184 static void cirrus_init_linear_fb(struct device *dev)
185 {
186 	uint8_t cr_ext, cr_overlay;
187 	unsigned int pitch = (width * 4) / VGA_CR_PITCH_DIVISOR;
188 	uint8_t sr_ext = 0, hidden_dac = 0;
189 	unsigned int vdisplay_end = height - 2;
190 	unsigned int line_compare = 0x3ff;
191 	uint8_t overflow, cell_height_reg;
192 	unsigned int horizontal_end = width / VGA_CR_WIDTH_DIVISOR;
193 	unsigned int horizontal_total = horizontal_end + 40;
194 	unsigned int horizontal_blank_start = horizontal_end;
195 	unsigned int horizontal_sync_pulse_start = horizontal_end + 3;
196 	unsigned int horizontal_sync_pulse_end = 0;
197 
198 	unsigned int horizontal_blank_end = 0;
199 	unsigned int vertical_blank_start = height + 1;
200 	unsigned int vertical_blank_end = 0;
201 	unsigned int vertical_sync_start = height + 3;
202 	unsigned int vertical_sync_end = 0;
203 	unsigned int vertical_total = height + 40;
204 
205 	/* find lfb pci bar */
206 	addr = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
207 	addr &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
208 	printk(BIOS_DEBUG, "QEMU VGA: cirrus framebuffer @ %x (pci bar 0)\n",
209 	       addr);
210 
211 	vga_misc_write(VGA_IO_MISC_COLOR);
212 
213 	vga_sr_write(VGA_SR_MEMORY_MODE,
214 		      VGA_SR_MEMORY_MODE_NORMAL);
215 
216 	vga_sr_write(VGA_SR_MAP_MASK_REGISTER,
217 		      (1 << VGA_TEXT_TEXT_PLANE)
218 		      | (1 << VGA_TEXT_ATTR_PLANE));
219 
220 	vga_sr_write(VGA_SR_CLOCKING_MODE,
221 		      VGA_SR_CLOCKING_MODE_8_DOT_CLOCK);
222 
223 	vga_palette_disable();
224 
225 	/* Disable CR0-7 write protection.  */
226 	vga_cr_write(VGA_CR_VSYNC_END, 0);
227 
228 	overflow = ((vertical_total >> VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT)
229 		    & VGA_CR_OVERFLOW_VERT_TOTAL1_MASK)
230 		| ((vertical_total >> VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT)
231 		   & VGA_CR_OVERFLOW_VERT_TOTAL2_MASK)
232 		| ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START2_SHIFT)
233 		   & VGA_CR_OVERFLOW_VSYNC_START2_MASK)
234 		| ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START1_SHIFT)
235 		   & VGA_CR_OVERFLOW_VSYNC_START1_MASK)
236 		| ((vdisplay_end >> VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT)
237 		   & VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK)
238 		| ((vdisplay_end >> VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT)
239 		   & VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK)
240 		| ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START1_SHIFT)
241 		   & VGA_CR_OVERFLOW_VSYNC_START1_MASK)
242 		| ((line_compare >> VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT)
243 		   & VGA_CR_OVERFLOW_LINE_COMPARE_MASK);
244 
245 	cell_height_reg = ((vertical_blank_start
246 			    >> VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT)
247 			   & VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK)
248 		| ((line_compare >> VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT)
249 		   & VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK);
250 
251 	vga_cr_write(VGA_CR_HTOTAL, horizontal_total - 1);
252 	vga_cr_write(VGA_CR_HORIZ_END, horizontal_end - 1);
253 	vga_cr_write(VGA_CR_HBLANK_START, horizontal_blank_start - 1);
254 	vga_cr_write(VGA_CR_HBLANK_END, horizontal_blank_end);
255 	vga_cr_write(VGA_CR_HORIZ_SYNC_PULSE_START,
256 		      horizontal_sync_pulse_start);
257 	vga_cr_write(VGA_CR_HORIZ_SYNC_PULSE_END,
258 		      horizontal_sync_pulse_end);
259 	vga_cr_write(VGA_CR_VERT_TOTAL, vertical_total & 0xff);
260 	vga_cr_write(VGA_CR_OVERFLOW, overflow);
261 	vga_cr_write(VGA_CR_CELL_HEIGHT, cell_height_reg);
262 	vga_cr_write(VGA_CR_VSYNC_START, vertical_sync_start & 0xff);
263 	vga_cr_write(VGA_CR_VSYNC_END, vertical_sync_end & 0x0f);
264 	vga_cr_write(VGA_CR_VDISPLAY_END, vdisplay_end & 0xff);
265 	vga_cr_write(VGA_CR_PITCH, pitch & 0xff);
266 	vga_cr_write(VGA_CR_VERTICAL_BLANK_START, vertical_blank_start & 0xff);
267 	vga_cr_write(VGA_CR_VERTICAL_BLANK_END, vertical_blank_end & 0xff);
268 	vga_cr_write(VGA_CR_LINE_COMPARE, line_compare & 0xff);
269 
270 	vga_gr_write(VGA_GR_MODE, VGA_GR_MODE_256_COLOR | VGA_GR_MODE_READ_MODE1);
271 	vga_gr_write(VGA_GR_GR6, VGA_GR_GR6_GRAPHICS_MODE);
272 
273 	vga_sr_write(VGA_SR_MEMORY_MODE, VGA_SR_MEMORY_MODE_NORMAL);
274 
275 	vga_cr_write(CIRRUS_CR_EXTENDED_DISPLAY,
276 		      (pitch >> CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT)
277 		      & CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK);
278 
279 	vga_cr_write(VGA_CR_MODE, VGA_CR_MODE_TIMING_ENABLE
280 		      | VGA_CR_MODE_BYTE_MODE
281 		      | VGA_CR_MODE_NO_HERCULES | VGA_CR_MODE_NO_CGA);
282 
283 	vga_cr_write(VGA_CR_START_ADDR_LOW_REGISTER, 0);
284 	vga_cr_write(VGA_CR_START_ADDR_HIGH_REGISTER, 0);
285 
286 	cr_ext = vga_cr_read(CIRRUS_CR_EXTENDED_DISPLAY);
287 	cr_ext &= ~(CIRRUS_CR_EXTENDED_DISPLAY_START_MASK1
288 		    | CIRRUS_CR_EXTENDED_DISPLAY_START_MASK2);
289 	vga_cr_write(CIRRUS_CR_EXTENDED_DISPLAY, cr_ext);
290 
291 	cr_overlay = vga_cr_read(CIRRUS_CR_EXTENDED_OVERLAY);
292 	cr_overlay &= ~(CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_MASK);
293 	vga_cr_write(CIRRUS_CR_EXTENDED_OVERLAY, cr_overlay);
294 
295 	sr_ext = CIRRUS_SR_EXTENDED_MODE_LFB_ENABLE
296 		| CIRRUS_SR_EXTENDED_MODE_ENABLE_EXT
297 		| CIRRUS_SR_EXTENDED_MODE_32BPP;
298 	hidden_dac = CIRRUS_HIDDEN_DAC_888COLOR;
299 	vga_sr_write(CIRRUS_SR_EXTENDED_MODE, sr_ext);
300 	write_hidden_dac(hidden_dac);
301 
302 	fb_add_framebuffer_info(addr, width, height, 4 * width, 32);
303 }
304 
cirrus_init_text_mode(struct device * dev)305 static void cirrus_init_text_mode(struct device *dev)
306 {
307 	vga_misc_write(0x1);
308 	vga_textmode_init();
309 }
310 
cirrus_init(struct device * dev)311 static void cirrus_init(struct device *dev)
312 {
313 	if (CONFIG(LINEAR_FRAMEBUFFER))
314 		cirrus_init_linear_fb(dev);
315 	else if (CONFIG(VGA_TEXT_FRAMEBUFFER))
316 		cirrus_init_text_mode(dev);
317 }
318 
319 static struct device_operations qemu_cirrus_graph_ops = {
320 	.read_resources	  = pci_dev_read_resources,
321 	.set_resources	  = pci_dev_set_resources,
322 	.enable_resources = pci_dev_enable_resources,
323 	.init		  = cirrus_init,
324 };
325 
326 static const struct pci_driver qemu_cirrus_driver __pci_driver = {
327 	.ops	= &qemu_cirrus_graph_ops,
328 	.vendor = 0x1013,
329 	.device = 0x00b8,
330 };
331