Patrick Georgi | c49d7a3 | 2020-05-08 22:50:46 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 2 | |
| 3 | #include <pc80/vga.h> |
| 4 | #include <pc80/vga_io.h> |
| 5 | |
| 6 | #include <string.h> |
Vikram Narayanan | cc16cca | 2012-01-25 20:40:40 +0530 | [diff] [blame] | 7 | #include "vga.h" |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 8 | |
| 9 | /* |
| 10 | * pci io enable should've happened before |
| 11 | */ |
| 12 | void |
| 13 | vga_io_init(void) |
| 14 | { |
| 15 | vga_enable_mask(0x01, 0x01); |
| 16 | |
| 17 | /* cr io is at 0x3D4/0x3D5 */ |
| 18 | vga_misc_mask(0x01, 0x01); |
| 19 | |
| 20 | /* clear cr0-7 protection */ |
| 21 | vga_cr_mask(0x11, 0x00, 0x80); |
| 22 | } |
| 23 | |
| 24 | /* |
| 25 | * |
| 26 | */ |
| 27 | static void |
| 28 | vga_fb_init(void) |
| 29 | { |
| 30 | vga_sr_write(0x02, 0x03); |
| 31 | vga_sr_write(0x03, 0x00); |
| 32 | vga_sr_write(0x04, 0x02); /* access all 256kB */ |
| 33 | |
| 34 | vga_gr_write(0x00, 0x00); |
| 35 | vga_gr_write(0x01, 0x00); |
| 36 | vga_gr_write(0x02, 0x00); |
| 37 | vga_gr_write(0x03, 0x00); |
| 38 | vga_gr_write(0x04, 0x00); |
| 39 | vga_gr_write(0x05, 0x10); |
| 40 | vga_gr_write(0x06, 0x0E); /* map at 0xB8000 */ |
| 41 | vga_gr_write(0x07, 0x00); |
| 42 | vga_gr_write(0x08, 0xFF); |
| 43 | |
Elyes HAOUAS | 7753731 | 2016-07-30 15:37:26 +0200 | [diff] [blame] | 44 | /* o/e enable: RAM enable */ |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 45 | vga_misc_mask(0x22, 0x22); |
| 46 | } |
| 47 | |
| 48 | /* |
| 49 | * |
| 50 | */ |
| 51 | static void |
| 52 | vga_fb_clear(void) |
| 53 | { |
| 54 | memset((void *)VGA_FB, 0x00, 0x8000); |
| 55 | } |
| 56 | |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 57 | /* |
| 58 | * |
| 59 | */ |
| 60 | static void |
| 61 | vga_palette_init(void) |
| 62 | { |
Jeremy Compostella | 355471a | 2022-12-07 17:08:03 -0700 | [diff] [blame] | 63 | size_t i; |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 64 | |
| 65 | /* set up attribute registers */ |
| 66 | for (i = 0; i < 0x10; i++) |
| 67 | vga_ar_write(i, i); |
| 68 | |
| 69 | vga_ar_write(0x10, 0x0c); |
| 70 | vga_ar_write(0x11, 0x00); |
| 71 | vga_ar_write(0x12, 0x0F); |
| 72 | vga_ar_write(0x13, 0x08); |
| 73 | vga_ar_write(0x14, 0x00); |
| 74 | |
| 75 | vga_palette_disable(); |
| 76 | |
| 77 | /* load actual palette */ |
| 78 | vga_dac_mask_write(0xFF); |
| 79 | |
| 80 | for (i = 0; i < 0x100; i++) { |
| 81 | vga_dac_write_address(i); |
| 82 | vga_dac_data_write(default_vga_palette[i].red); |
| 83 | vga_dac_data_write(default_vga_palette[i].green); |
| 84 | vga_dac_data_write(default_vga_palette[i].blue); |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | /* |
| 89 | * |
| 90 | */ |
| 91 | static void |
| 92 | vga_mode_set(int hdisplay, int hblankstart, int hsyncstart, int hsyncend, |
| 93 | int hblankend, int htotal, int vdisplay, int vblankstart, |
| 94 | int vsyncstart, int vsyncend, int vblankend, int vtotal, |
| 95 | int stride) |
| 96 | { |
| 97 | /* htotal: 2080 */ |
| 98 | htotal /= 8; |
| 99 | htotal -= 5; |
| 100 | vga_cr_write(0x00, htotal); |
| 101 | |
| 102 | /* hdisplay: 2048 */ |
| 103 | hdisplay /= 8; |
| 104 | hdisplay -= 1; |
| 105 | vga_cr_write(0x01, hdisplay); |
| 106 | |
| 107 | /* hblankstart: 2048 */ |
| 108 | hblankstart /= 8; |
| 109 | hblankstart -= 1; |
| 110 | vga_cr_write(0x02, hblankstart); |
| 111 | |
| 112 | /* hblankend: hblankstart + 512 */ |
| 113 | hblankend /= 8; |
| 114 | hblankend -= 1; |
| 115 | vga_cr_mask(0x03, hblankend, 0x1F); |
| 116 | vga_cr_mask(0x05, hblankend << 2, 0x80); |
| 117 | |
| 118 | /* hsyncstart: 255 * 8: 2040 */ |
| 119 | vga_cr_write(0x04, hsyncstart / 8); |
| 120 | |
| 121 | /* hsyncend: hsyncstart + 255 */ |
| 122 | vga_cr_mask(0x05, hsyncend / 8, 0x1F); |
| 123 | |
| 124 | /* vtotal: 1025 */ |
| 125 | vtotal -= 2; |
| 126 | vga_cr_write(0x06, vtotal); |
| 127 | vga_cr_mask(0x07, vtotal >> 8, 0x01); |
| 128 | vga_cr_mask(0x07, vtotal >> 4, 0x20); |
| 129 | |
| 130 | /* vdisplay: 1024 */ |
| 131 | vdisplay -= 1; |
| 132 | vga_cr_write(0x12, vdisplay); |
| 133 | vga_cr_mask(0x07, vdisplay >> 7, 0x02); |
| 134 | vga_cr_mask(0x07, vdisplay >> 3, 0x40); |
| 135 | |
| 136 | /* vblankstart: 1024 */ |
| 137 | vblankstart -= 1; |
| 138 | vga_cr_write(0x15, vblankstart); |
| 139 | vga_cr_mask(0x07, vblankstart >> 5, 0x08); |
| 140 | vga_cr_mask(0x09, vblankstart >> 4, 0x20); |
| 141 | |
| 142 | /* vblankend: vblankstart + 256 */ |
| 143 | vblankend -= 1; |
| 144 | vga_cr_write(0x16, vblankend); |
| 145 | |
| 146 | /* vsyncstart: 1023 */ |
| 147 | vga_cr_write(0x10, vsyncstart); |
| 148 | vga_cr_mask(0x07, vsyncstart >> 6, 0x04); |
| 149 | vga_cr_mask(0x07, vsyncstart >> 2, 0x80); |
| 150 | |
| 151 | /* vsyncend: vsyncstart + 16 */ |
| 152 | vga_cr_mask(0x11, vsyncend, 0x0F); |
| 153 | |
| 154 | /* stride */ |
| 155 | vga_cr_write(0x13, stride / 8); |
| 156 | |
| 157 | /* line compare */ |
| 158 | vga_cr_write(0x18, 0xFF); |
| 159 | vga_cr_mask(0x07, 0x10, 0x10); |
| 160 | vga_cr_mask(0x09, 0x40, 0x40); |
| 161 | |
| 162 | vga_misc_mask(0x44, 0xCC); /* set up clock: 27mhz and h/vsync */ |
| 163 | |
| 164 | vga_cr_mask(0x09, 0x00, 0x80); /* disable doublescan */ |
| 165 | } |
| 166 | |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 167 | static void |
| 168 | vga_font_8x16_load(void) |
| 169 | { |
| 170 | unsigned char *p; |
Jeremy Compostella | 355471a | 2022-12-07 17:08:03 -0700 | [diff] [blame] | 171 | size_t i, j; |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 172 | unsigned char sr2, sr4, gr5, gr6; |
| 173 | |
| 174 | #define height 16 |
| 175 | #define count 256 |
| 176 | |
| 177 | sr2 = vga_sr_read(0x02); |
| 178 | sr4 = vga_sr_read(0x04); |
| 179 | gr5 = vga_gr_read(0x05); |
| 180 | gr6 = vga_gr_read(0x06); |
| 181 | |
| 182 | /* disable odd/even */ |
| 183 | vga_sr_mask(0x04, 0x04, 0x04); |
| 184 | vga_gr_mask(0x05, 0x00, 0x10); |
| 185 | vga_gr_mask(0x06, 0x00, 0x02); |
| 186 | |
| 187 | /* plane 2 */ |
| 188 | vga_sr_write(0x02, 0x04); |
Elyes Haouas | 1ef547e | 2022-11-18 15:05:39 +0100 | [diff] [blame] | 189 | p = (unsigned char *)VGA_FB; |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 190 | for (i = 0; i < count; i++) { |
| 191 | for (j = 0; j < 32; j++) { |
| 192 | if (j < height) |
| 193 | *p = vga_font_8x16[i][j]; |
| 194 | else |
| 195 | *p = 0x00; |
| 196 | p++; |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | vga_gr_write(0x06, gr6); |
| 201 | vga_gr_write(0x05, gr5); |
| 202 | vga_sr_write(0x04, sr4); |
| 203 | vga_sr_write(0x02, sr2); |
| 204 | |
| 205 | /* set up font size */ |
| 206 | vga_cr_mask(0x09, 16 - 1, 0x1F); |
| 207 | } |
| 208 | |
| 209 | /* |
| 210 | * |
| 211 | */ |
| 212 | void |
| 213 | vga_cursor_enable(int enable) |
| 214 | { |
| 215 | if (enable) |
| 216 | vga_cr_mask(0x0A, 0x00, 0x20); |
| 217 | else |
| 218 | vga_cr_mask(0x0A, 0x20, 0x20); |
| 219 | } |
| 220 | |
| 221 | /* |
| 222 | * |
| 223 | */ |
| 224 | void |
| 225 | vga_cursor_reset(void) |
| 226 | { |
| 227 | vga_cr_write(0x0A, 0x2E); |
| 228 | vga_cr_write(0x0B, 0x0E); |
| 229 | vga_cr_write(0x0E, 0x00); |
| 230 | vga_cr_write(0x0F, 0x00); |
| 231 | } |
| 232 | |
| 233 | /* |
| 234 | * |
| 235 | */ |
| 236 | void |
| 237 | vga_cursor_set(unsigned int line, unsigned int character) |
| 238 | { |
Jeremy Compostella | 355471a | 2022-12-07 17:08:03 -0700 | [diff] [blame] | 239 | unsigned int offset = (VGA_COLUMNS * line + character) & 0xFFFF; |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 240 | |
| 241 | vga_cr_write(0x0A, 0x0E); |
| 242 | vga_cr_write(0x0B, 0x0E); |
| 243 | vga_cr_write(0x0E, offset >> 8); |
| 244 | vga_cr_write(0x0F, offset & 0xFF); |
| 245 | } |
| 246 | |
| 247 | /* |
| 248 | * |
| 249 | */ |
| 250 | void |
| 251 | vga_frame_set(unsigned int line, unsigned int character) |
| 252 | { |
Jeremy Compostella | 355471a | 2022-12-07 17:08:03 -0700 | [diff] [blame] | 253 | unsigned int offset = (VGA_COLUMNS * line + character) & 0xFFFF; |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 254 | |
| 255 | vga_cr_write(0x0C, offset >> 8); |
| 256 | vga_cr_write(0x0D, offset & 0xFF); |
| 257 | } |
| 258 | |
Subrata Banik | 3e3b78a | 2022-12-26 21:39:59 +0530 | [diff] [blame^] | 259 | static void |
| 260 | vga_write_at_offset(unsigned int line, unsigned int offset, const char *string) |
| 261 | { |
| 262 | if (!string) |
| 263 | return; |
| 264 | |
| 265 | unsigned short *p = (unsigned short *)VGA_FB + (VGA_COLUMNS * line) + offset; |
| 266 | size_t i, len = strlen(string); |
| 267 | |
| 268 | for (i = 0; i < (VGA_COLUMNS - offset); i++) { |
| 269 | if (i < len) |
| 270 | p[i] = 0x0F00 | string[i]; |
| 271 | else |
| 272 | p[i] = 0x0F00; |
| 273 | } |
| 274 | } |
| 275 | |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 276 | /* |
| 277 | * simply fills a line with the given string. |
| 278 | */ |
| 279 | void |
| 280 | vga_line_write(unsigned int line, const char *string) |
| 281 | { |
Subrata Banik | 3e3b78a | 2022-12-26 21:39:59 +0530 | [diff] [blame^] | 282 | vga_write_at_offset(line, 0, string); |
| 283 | } |
Subrata Banik | 25b717a | 2022-12-25 16:54:30 +0530 | [diff] [blame] | 284 | |
Subrata Banik | 3e3b78a | 2022-12-26 21:39:59 +0530 | [diff] [blame^] | 285 | void |
| 286 | vga_write_text(enum VGA_TEXT_ALIGNMENT alignment, unsigned int line, const char *string) |
| 287 | { |
| 288 | char str[VGA_COLUMNS * VGA_LINES] = {0}; |
| 289 | memcpy(str, string, strnlen(string, sizeof(str) - 1)); |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 290 | |
Subrata Banik | 3e3b78a | 2022-12-26 21:39:59 +0530 | [diff] [blame^] | 291 | char *token = strtok(str, "\n"); |
| 292 | |
| 293 | while (token != NULL) { |
| 294 | size_t offset = VGA_COLUMNS - strnlen(token, VGA_COLUMNS); |
| 295 | switch (alignment) { |
| 296 | case VGA_TEXT_CENTER: |
| 297 | vga_write_at_offset(line++, offset/2, token); |
| 298 | break; |
| 299 | case VGA_TEXT_RIGHT: |
| 300 | vga_write_at_offset(line++, offset, token); |
| 301 | break; |
| 302 | case VGA_TEXT_LEFT: |
| 303 | default: |
| 304 | vga_write_at_offset(line++, 0, token); |
| 305 | break; |
| 306 | } |
| 307 | token = strtok(NULL, "\n"); |
Luc Verhaegen | 5c5beb7 | 2009-05-29 03:04:16 +0000 | [diff] [blame] | 308 | } |
| 309 | } |
| 310 | |
| 311 | /* |
| 312 | * set up everything to get a basic 80x25 textmode. |
| 313 | */ |
| 314 | void |
| 315 | vga_textmode_init(void) |
| 316 | { |
| 317 | vga_sr_write(0x00, 0x01); /* clear reset */ |
| 318 | vga_sr_write(0x01, 0x00); |
| 319 | |
| 320 | /* set up cr */ |
| 321 | vga_cr_mask(0x03, 0x80, 0xE0); |
| 322 | vga_cr_mask(0x05, 0x00, 0x60); |
| 323 | |
| 324 | vga_cr_write(0x08, 0x00); |
| 325 | |
| 326 | vga_cr_write(0x14, 0x00); /* */ |
| 327 | |
| 328 | vga_cr_write(0x17, 0x23); |
| 329 | |
| 330 | vga_palette_init(); |
| 331 | |
| 332 | vga_mode_set(640, 648, 680, 776, 792, 800, |
| 333 | 400, 407, 412, 414, 442, 449, 320); |
| 334 | |
| 335 | vga_cursor_reset(); |
| 336 | vga_frame_set(0, 0); |
| 337 | |
| 338 | vga_fb_init(); |
| 339 | vga_fb_clear(); |
| 340 | vga_font_8x16_load(); |
| 341 | |
| 342 | vga_sr_mask(0x00, 0x02, 0x02); /* take us out of reset */ |
| 343 | vga_cr_mask(0x17, 0x80, 0x80); /* sync! */ |
| 344 | } |