1/*- 2 * Copyright (c) 2012 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD$"); 33 34#include <sys/param.h> 35#include <sys/bus.h> 36#include <sys/conf.h> 37#include <sys/consio.h> 38#include <sys/fbio.h> 39#include <sys/kbio.h> 40#include <sys/kernel.h> 41#include <sys/lock.h> 42#include <sys/malloc.h> 43#include <sys/mutex.h> 44#include <sys/module.h> 45#include <sys/rman.h> 46#include <sys/systm.h> 47#include <sys/uio.h> 48 49#include <machine/bus.h> 50#include <machine/resource.h> 51#include <machine/vm.h> 52 53#include <dev/fb/fbreg.h> 54 55#include <dev/kbd/kbdreg.h> 56 57#include <dev/syscons/syscons.h> 58 59#include <dev/terasic/mtl/terasic_mtl.h> 60 61/* 62 * Terasic Multitouch LCD (MTL) syscons driver. Implement syscons(4)'s 63 * video_switch_t KPI using MTL's text frame buffer. In principle, we could 64 * actually implement sc_rndr_sw_t, since the MTL text frame buffer implements 65 * a VGA-like memory mapping. However, this requires a lot more book-keeping 66 * with only minor performance improvements (avoiding indirection), as well as 67 * introducing potential endianness issues. Instead we accept one additional 68 * memory copy between a software frame buffer and the hardware frame buffer 69 * and the generic frame buffer (gfb) framework. 70 */ 71 72MALLOC_DEFINE(M_TERASIC_MTL, "mtl_syscons", "MTL syscons frame buffer"); 73 74/* 75 * Run early so that boot-time console support can be initialised before 76 * newbus gets around to configuring syscons. 77 * 78 * XXXRW: We may need to do more here in order to see earlier boot messages. 79 */ 80static int 81terasic_mtl_syscons_configure(int flags) 82{ 83 84 printf("%s: not yet\n", __func__); 85 return (0); 86} 87 88static int 89terasic_mtl_vidsw_probe(int unit, video_adapter_t **adp, void *args, 90 int flags) 91{ 92 93 printf("%s: not yet\n", __func__); 94 return (0); 95} 96 97static int 98terasic_mtl_vidsw_init(int unit, video_adapter_t *adp, int flags) 99{ 100 struct terasic_mtl_softc *sc; 101 video_info_t *vi; 102 103 sc = (struct terasic_mtl_softc *)adp; 104 105 vi = &adp->va_info; 106 vid_init_struct(adp, "terasic_mtl_syscons", -1, unit); 107 108 vi->vi_width = TERASIC_MTL_COLS; 109 if (vi->vi_width > COL) 110 vi->vi_width = COL; 111 vi->vi_height = TERASIC_MTL_ROWS; 112 if (vi->vi_height > ROW) 113 vi->vi_height = ROW; 114 115 /* 116 * XXXRW: It's not quite clear how these should be initialised. 117 */ 118 vi->vi_cwidth = 0; 119 vi->vi_cheight = 0; 120 vi->vi_flags = V_INFO_COLOR; 121 vi->vi_mem_model = V_INFO_MM_OTHER; 122 123 /* 124 * Software text frame buffer from which we update the actual MTL 125 * frame buffer when asked to. 126 */ 127 adp->va_window = (vm_offset_t)sc->mtl_text_soft; 128 129 /* 130 * Declare video adapter capabilities -- at this point, simply color 131 * support, as MTL doesn't support screen borders, font loading, or 132 * mode changes. 133 * 134 * XXXRW: It's unclear if V_ADP_INITIALIZED is needed here; other 135 * syscons(4) drivers are inconsistent about this and 136 * V_ADP_REGISTERED. 137 */ 138 adp->va_flags |= V_ADP_COLOR | V_ADP_INITIALIZED; 139 if (vid_register(adp) < 0) { 140 device_printf(sc->mtl_dev, "%s: vid_register failed\n", 141 __func__); 142 return (ENXIO); 143 } 144 adp->va_flags |= V_ADP_REGISTERED; 145 return (0); 146} 147 148static int 149terasic_mtl_vidsw_get_info(video_adapter_t *adp, int mode, video_info_t *info) 150{ 151 152 bcopy(&adp->va_info, info, sizeof(*info)); 153 return (0); 154} 155 156static int 157terasic_mtl_vidsw_query_mode(video_adapter_t *adp, video_info_t *info) 158{ 159 160 printf("%s: not yet\n", __func__); 161 return (ENODEV); 162} 163 164static int 165terasic_mtl_vidsw_set_mode(video_adapter_t *adp, int mode) 166{ 167 168 printf("%s: not yet\n", __func__); 169 return (ENODEV); 170} 171 172static int 173terasic_mtl_vidsw_save_font(video_adapter_t *adp, int page, int size, 174 int width, u_char *data, int c, int count) 175{ 176 177 printf("%s: not yet\n", __func__); 178 return (ENODEV); 179} 180 181static int 182terasic_mtl_vidsw_load_font(video_adapter_t *adp, int page, int size, 183 int width, u_char *data, int c, int count) 184{ 185 186 printf("%s: not yet\n", __func__); 187 return (ENODEV); 188} 189 190static int 191terasic_mtl_vidsw_show_font(video_adapter_t *adp, int page) 192{ 193 194 printf("%s: not yet\n", __func__); 195 return (ENODEV); 196} 197 198static int 199terasic_mtl_vidsw_save_palette(video_adapter_t *adp, u_char *palette) 200{ 201 202 printf("%s: not yet\n", __func__); 203 return (ENODEV); 204} 205 206static int 207terasic_mtl_vidsw_load_palette(video_adapter_t *adp, u_char *palette) 208{ 209 210 printf("%s: not yet\n", __func__); 211 return (ENODEV); 212} 213 214static int 215terasic_mtl_vidsw_set_border(video_adapter_t *adp, int border) 216{ 217 218 printf("%s: not yet\n", __func__); 219 return (ENODEV); 220} 221 222static int 223terasic_mtl_vidsw_save_state(video_adapter_t *adp, void *p, size_t size) 224{ 225 226 printf("%s: not yet\n", __func__); 227 return (ENODEV); 228} 229 230static int 231terasic_mtl_vidsw_load_state(video_adapter_t *adp, void *p) 232{ 233 234 printf("%s: not yet\n", __func__); 235 return (ENODEV); 236} 237 238static int 239terasic_mtl_vidsw_set_win_org(video_adapter_t *adp, off_t offset) 240{ 241 242 printf("%s: not yet\n", __func__); 243 return (ENODEV); 244} 245 246static int 247terasic_mtl_vidsw_read_hw_cursor(video_adapter_t *adp, int *colp, int *rowp) 248{ 249 struct terasic_mtl_softc *sc; 250 uint8_t col, row; 251 252 sc = (struct terasic_mtl_softc *)adp; 253 terasic_mtl_reg_textcursor_get(sc, &col, &row); 254 *colp = col; 255 *rowp = row; 256 return (0); 257} 258 259static int 260terasic_mtl_vidsw_set_hw_cursor(video_adapter_t *adp, int col, int row) 261{ 262 struct terasic_mtl_softc *sc; 263 264 sc = (struct terasic_mtl_softc *)adp; 265 terasic_mtl_reg_textcursor_set(sc, col, row); 266 return (0); 267} 268 269static int 270terasic_mtl_vidsw_set_hw_cursor_shape(video_adapter_t *adp, int base, 271 int height, int celsize, int blink) 272{ 273 274 printf("%s: not yet\n", __func__); 275 return (ENODEV); 276} 277 278static int 279terasic_mtl_vidsw_blank_display(video_adapter_t *adp, int mode) 280{ 281 struct terasic_mtl_softc *sc; 282 283 sc = (struct terasic_mtl_softc *)adp; 284 terasic_mtl_reg_blank(sc); 285 return (0); 286} 287 288static int 289terasic_mtl_vidsw_mmap(video_adapter_t *adp, vm_ooffset_t offset, 290 vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) 291{ 292 293 printf("%s: not yet\n", __func__); 294 return (ENODEV); 295} 296 297static int 298terasic_mtl_vidsw_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data) 299{ 300 301 return (fb_commonioctl(adp, cmd, data)); 302} 303 304static int 305terasic_mtl_vidsw_clear(video_adapter_t *adp) 306{ 307 struct terasic_mtl_softc *sc; 308 309 sc = (struct terasic_mtl_softc *)adp; 310 printf("%s: not yet terasic_mtl_io_clear(sc);\n", __func__); 311 return (0); 312} 313 314static int 315terasic_mtl_vidsw_fill_rect(video_adapter_t *adp, int val, int x, int y, 316 int cx, int cy) 317{ 318 319 printf("%s: not yet\n", __func__); 320 return (ENODEV); 321} 322 323static int 324terasic_mtl_vidsw_bitblt(video_adapter_t *adp, ...) 325{ 326 327 printf("%s: not yet\n", __func__); 328 return (ENODEV); 329} 330 331static int 332terasic_mtl_vidsw_diag(video_adapter_t *adp, int level) 333{ 334 335 printf("%s: not yet\n", __func__); 336 return (ENODEV); 337} 338 339static int 340terasic_mtl_vidsw_save_cursor_palette(video_adapter_t *adp, u_char *palette) 341{ 342 343 printf("%s: not yet\n", __func__); 344 return (ENODEV); 345} 346 347static int 348terasic_mtl_vidsw_load_cursor_palette(video_adapter_t *adp, u_char *palette) 349{ 350 351 printf("%s: not yet\n", __func__); 352 return (ENODEV); 353} 354 355static int 356terasic_mtl_vidsw_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, 357 int n) 358{ 359 360 printf("%s: not yet\n", __func__); 361 return (ENODEV); 362} 363 364static int 365terasic_mtl_vidsw_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, 366 uint32_t a, int size, int bpp, int bit_ltor, int byte_ltor) 367{ 368 369 printf("%s: not yet\n", __func__); 370 return (ENODEV); 371} 372 373static int 374terasic_mtl_vidsw_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, 375 uint8_t a) 376{ 377 struct terasic_mtl_softc *sc; 378 u_int col, row; 379 380 sc = (struct terasic_mtl_softc *)adp; 381 col = (off % adp->va_info.vi_width); 382 row = (off / adp->va_info.vi_width); 383 terasic_mtl_text_putc(sc, col, row, c, a); 384 return (0); 385} 386 387static int 388terasic_mtl_vidsw_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, 389 int len) 390{ 391 int i; 392 393 for (i = 0; i < len; i++) 394 vidd_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8); 395 return (0); 396} 397 398static int 399terasic_mtl_vidsw_putm(video_adapter_t *adp, int x, int y, 400 uint8_t *pixel_image, uint32_t pixel_mask, int size, int width) 401{ 402 403 printf("%s: not yet\n", __func__); 404 return (ENODEV); 405} 406 407/* 408 * XXXRW: For historical reasons, syscons can't register video consoles 409 * without a keyboard implementation. Provide a dummy. 410 */ 411static keyboard_switch_t terasic_mtl_keyboard_switch; 412 413static int 414terasic_mtl_kbd_configure(int flags) 415{ 416 417 return (0); 418} 419 420KEYBOARD_DRIVER(mtl_kbd, terasic_mtl_keyboard_switch, 421 terasic_mtl_kbd_configure); 422 423int 424terasic_mtl_syscons_attach(struct terasic_mtl_softc *sc) 425{ 426 int error; 427 428 sc->mtl_text_soft = 429 malloc(sizeof(uint16_t) * TERASIC_MTL_ROWS * TERASIC_MTL_COLS, 430 M_TERASIC_MTL, M_WAITOK | M_ZERO); 431 error = terasic_mtl_vidsw_init(0, &sc->mtl_va, 0); 432 if (error) 433 goto out; 434 error = sc_attach_unit(sc->mtl_unit, device_get_flags(sc->mtl_dev) | 435 SC_AUTODETECT_KBD); 436 if (error) 437 device_printf(sc->mtl_dev, "%s: sc_attach_unit failed (%d)\n", 438 __func__, error); 439out: 440 if (error) 441 free(sc->mtl_text_soft, M_TERASIC_MTL); 442 return (error); 443} 444 445void 446terasic_mtl_syscons_detach(struct terasic_mtl_softc *sc) 447{ 448 449 free(sc->mtl_text_soft, M_TERASIC_MTL); 450 panic("%s: not supported by syscons", __func__); 451} 452 453static video_switch_t terasic_mtl_vidsw = { 454 .probe = terasic_mtl_vidsw_probe, 455 .init = terasic_mtl_vidsw_init, 456 .get_info = terasic_mtl_vidsw_get_info, 457 .query_mode = terasic_mtl_vidsw_query_mode, 458 .set_mode = terasic_mtl_vidsw_set_mode, 459 .save_font = terasic_mtl_vidsw_save_font, 460 .load_font = terasic_mtl_vidsw_load_font, 461 .show_font = terasic_mtl_vidsw_show_font, 462 .save_palette = terasic_mtl_vidsw_save_palette, 463 .load_palette = terasic_mtl_vidsw_load_palette, 464 .set_border = terasic_mtl_vidsw_set_border, 465 .save_state = terasic_mtl_vidsw_save_state, 466 .load_state = terasic_mtl_vidsw_load_state, 467 .set_win_org = terasic_mtl_vidsw_set_win_org, 468 .read_hw_cursor = terasic_mtl_vidsw_read_hw_cursor, 469 .set_hw_cursor = terasic_mtl_vidsw_set_hw_cursor, 470 .set_hw_cursor_shape = terasic_mtl_vidsw_set_hw_cursor_shape, 471 .blank_display = terasic_mtl_vidsw_blank_display, 472 .mmap = terasic_mtl_vidsw_mmap, 473 .ioctl = terasic_mtl_vidsw_ioctl, 474 .clear = terasic_mtl_vidsw_clear, 475 .fill_rect = terasic_mtl_vidsw_fill_rect, 476 .bitblt = terasic_mtl_vidsw_bitblt, 477 .diag = terasic_mtl_vidsw_diag, 478 .save_cursor_palette = terasic_mtl_vidsw_save_cursor_palette, 479 .load_cursor_palette = terasic_mtl_vidsw_load_cursor_palette, 480 .copy = terasic_mtl_vidsw_copy, 481 .putp = terasic_mtl_vidsw_putp, 482 .putc = terasic_mtl_vidsw_putc, 483 .puts = terasic_mtl_vidsw_puts, 484 .putm = terasic_mtl_vidsw_putm, 485}; 486VIDEO_DRIVER(terasic_mtl_syscons, terasic_mtl_vidsw, 487 terasic_mtl_syscons_configure); 488extern sc_rndr_sw_t txtrndrsw; 489RENDERER(terasic_mtl_syscons, 0, txtrndrsw, gfb_set); 490RENDERER_MODULE(terasic_mtl_syscons, gfb_set); 491