| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: genfb.c,v 1.80 2021/01/26 18:08:33 macallan Exp $ */ | | 1 | /* $NetBSD: genfb.c,v 1.81 2021/01/27 22:42:53 macallan Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 Michael Lorenz | | 4 | * Copyright (c) 2007 Michael Lorenz |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -17,27 +17,27 @@ | | | @@ -17,27 +17,27 @@ |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. | | 26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: genfb.c,v 1.80 2021/01/26 18:08:33 macallan Exp $"); | | 30 | __KERNEL_RCSID(0, "$NetBSD: genfb.c,v 1.81 2021/01/27 22:42:53 macallan Exp $"); |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/systm.h> | | 33 | #include <sys/systm.h> |
34 | #include <sys/kernel.h> | | 34 | #include <sys/kernel.h> |
35 | #include <sys/device.h> | | 35 | #include <sys/device.h> |
36 | #include <sys/proc.h> | | 36 | #include <sys/proc.h> |
37 | #include <sys/mutex.h> | | 37 | #include <sys/mutex.h> |
38 | #include <sys/ioctl.h> | | 38 | #include <sys/ioctl.h> |
39 | #include <sys/kernel.h> | | 39 | #include <sys/kernel.h> |
40 | #include <sys/systm.h> | | 40 | #include <sys/systm.h> |
41 | #include <sys/kmem.h> | | 41 | #include <sys/kmem.h> |
42 | #include <sys/reboot.h> | | 42 | #include <sys/reboot.h> |
43 | | | 43 | |
| @@ -82,26 +82,31 @@ static void genfb_pollc(void *, int); | | | @@ -82,26 +82,31 @@ static void genfb_pollc(void *, int); |
82 | static void genfb_init_screen(void *, struct vcons_screen *, int, long *); | | 82 | static void genfb_init_screen(void *, struct vcons_screen *, int, long *); |
83 | static int genfb_calc_hsize(struct genfb_softc *); | | 83 | static int genfb_calc_hsize(struct genfb_softc *); |
84 | static int genfb_calc_cols(struct genfb_softc *); | | 84 | static int genfb_calc_cols(struct genfb_softc *); |
85 | | | 85 | |
86 | static int genfb_putcmap(struct genfb_softc *, struct wsdisplay_cmap *); | | 86 | static int genfb_putcmap(struct genfb_softc *, struct wsdisplay_cmap *); |
87 | static int genfb_getcmap(struct genfb_softc *, struct wsdisplay_cmap *); | | 87 | static int genfb_getcmap(struct genfb_softc *, struct wsdisplay_cmap *); |
88 | static int genfb_putpalreg(struct genfb_softc *, uint8_t, uint8_t, | | 88 | static int genfb_putpalreg(struct genfb_softc *, uint8_t, uint8_t, |
89 | uint8_t, uint8_t); | | 89 | uint8_t, uint8_t); |
90 | static void genfb_init_palette(struct genfb_softc *); | | 90 | static void genfb_init_palette(struct genfb_softc *); |
91 | | | 91 | |
92 | static void genfb_brightness_up(device_t); | | 92 | static void genfb_brightness_up(device_t); |
93 | static void genfb_brightness_down(device_t); | | 93 | static void genfb_brightness_down(device_t); |
94 | | | 94 | |
| | | 95 | #if GENFB_GLYPHCACHE > 0 |
| | | 96 | static int genfb_setup_glyphcache(struct genfb_softc *, long); |
| | | 97 | static void genfb_putchar(void *, int, int, u_int, long); |
| | | 98 | #endif |
| | | 99 | |
95 | extern const u_char rasops_cmap[768]; | | 100 | extern const u_char rasops_cmap[768]; |
96 | | | 101 | |
97 | static int genfb_cnattach_called = 0; | | 102 | static int genfb_cnattach_called = 0; |
98 | static int genfb_enabled = 1; | | 103 | static int genfb_enabled = 1; |
99 | | | 104 | |
100 | static struct genfb_softc *genfb_softc = NULL; | | 105 | static struct genfb_softc *genfb_softc = NULL; |
101 | | | 106 | |
102 | void | | 107 | void |
103 | genfb_init(struct genfb_softc *sc) | | 108 | genfb_init(struct genfb_softc *sc) |
104 | { | | 109 | { |
105 | prop_dictionary_t dict; | | 110 | prop_dictionary_t dict; |
106 | uint64_t cmap_cb, pmf_cb, mode_cb, bl_cb, br_cb, fbaddr; | | 111 | uint64_t cmap_cb, pmf_cb, mode_cb, bl_cb, br_cb, fbaddr; |
107 | uint64_t fboffset; | | 112 | uint64_t fboffset; |
| @@ -278,26 +283,30 @@ genfb_attach(struct genfb_softc *sc, str | | | @@ -278,26 +283,30 @@ genfb_attach(struct genfb_softc *sc, str |
278 | vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, | | 283 | vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, |
279 | &sc->sc_accessops); | | 284 | &sc->sc_accessops); |
280 | sc->vd.init_screen = genfb_init_screen; | | 285 | sc->vd.init_screen = genfb_init_screen; |
281 | | | 286 | |
282 | /* Do not print anything between this point and the screen | | 287 | /* Do not print anything between this point and the screen |
283 | * clear operation below. Otherwise it will be lost. */ | | 288 | * clear operation below. Otherwise it will be lost. */ |
284 | | | 289 | |
285 | ri = &sc->sc_console_screen.scr_ri; | | 290 | ri = &sc->sc_console_screen.scr_ri; |
286 | | | 291 | |
287 | vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, | | 292 | vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, |
288 | &defattr); | | 293 | &defattr); |
289 | sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; | | 294 | sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; |
290 | | | 295 | |
| | | 296 | #if GENFB_GLYPHCACHE > 0 |
| | | 297 | genfb_setup_glyphcache(sc, defattr); |
| | | 298 | #endif |
| | | 299 | |
291 | #ifdef SPLASHSCREEN | | 300 | #ifdef SPLASHSCREEN |
292 | /* | | 301 | /* |
293 | * If system isn't going to go multiuser, or user has requested to see | | 302 | * If system isn't going to go multiuser, or user has requested to see |
294 | * boot text, don't render splash screen immediately | | 303 | * boot text, don't render splash screen immediately |
295 | */ | | 304 | */ |
296 | if (DISABLESPLASH) | | 305 | if (DISABLESPLASH) |
297 | #endif | | 306 | #endif |
298 | vcons_redraw_screen(&sc->sc_console_screen); | | 307 | vcons_redraw_screen(&sc->sc_console_screen); |
299 | | | 308 | |
300 | sc->sc_defaultscreen_descr.textops = &ri->ri_ops; | | 309 | sc->sc_defaultscreen_descr.textops = &ri->ri_ops; |
301 | sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; | | 310 | sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; |
302 | sc->sc_defaultscreen_descr.nrows = ri->ri_rows; | | 311 | sc->sc_defaultscreen_descr.nrows = ri->ri_rows; |
303 | sc->sc_defaultscreen_descr.ncols = ri->ri_cols; | | 312 | sc->sc_defaultscreen_descr.ncols = ri->ri_cols; |
| @@ -622,27 +631,30 @@ genfb_init_screen(void *cookie, struct v | | | @@ -622,27 +631,30 @@ genfb_init_screen(void *cookie, struct v |
622 | default: | | 631 | default: |
623 | break; | | 632 | break; |
624 | } | | 633 | } |
625 | | | 634 | |
626 | wantcols = genfb_calc_cols(sc); | | 635 | wantcols = genfb_calc_cols(sc); |
627 | | | 636 | |
628 | rasops_init(ri, 0, wantcols); | | 637 | rasops_init(ri, 0, wantcols); |
629 | ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | | | 638 | ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | |
630 | WSSCREEN_RESIZE; | | 639 | WSSCREEN_RESIZE; |
631 | rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, | | 640 | rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, |
632 | sc->sc_width / ri->ri_font->fontwidth); | | 641 | sc->sc_width / ri->ri_font->fontwidth); |
633 | | | 642 | |
634 | ri->ri_hw = scr; | | 643 | ri->ri_hw = scr; |
635 | | | 644 | #if GENFB_GLYPHCACHE > 0 |
| | | 645 | sc->sc_putchar = ri->ri_ops.putchar; |
| | | 646 | ri->ri_ops.putchar = genfb_putchar; |
| | | 647 | #endif |
636 | #ifdef GENFB_DISABLE_TEXT | | 648 | #ifdef GENFB_DISABLE_TEXT |
637 | if (scr == &sc->sc_console_screen && !DISABLESPLASH) | | 649 | if (scr == &sc->sc_console_screen && !DISABLESPLASH) |
638 | SCREEN_DISABLE_DRAWING(&sc->sc_console_screen); | | 650 | SCREEN_DISABLE_DRAWING(&sc->sc_console_screen); |
639 | #endif | | 651 | #endif |
640 | } | | 652 | } |
641 | | | 653 | |
642 | /* Returns the width of the display in millimeters, or 0 if not known. */ | | 654 | /* Returns the width of the display in millimeters, or 0 if not known. */ |
643 | static int | | 655 | static int |
644 | genfb_calc_hsize(struct genfb_softc *sc) | | 656 | genfb_calc_hsize(struct genfb_softc *sc) |
645 | { | | 657 | { |
646 | device_t dev = sc->sc_dev; | | 658 | device_t dev = sc->sc_dev; |
647 | prop_dictionary_t dict = device_properties(dev); | | 659 | prop_dictionary_t dict = device_properties(dev); |
648 | prop_data_t edid_data; | | 660 | prop_data_t edid_data; |
| @@ -880,13 +892,181 @@ genfb_enable_polling(device_t dev) | | | @@ -880,13 +892,181 @@ genfb_enable_polling(device_t dev) |
880 | } | | 892 | } |
881 | | | 893 | |
882 | void | | 894 | void |
883 | genfb_disable_polling(device_t dev) | | 895 | genfb_disable_polling(device_t dev) |
884 | { | | 896 | { |
885 | struct genfb_softc *sc = device_private(dev); | | 897 | struct genfb_softc *sc = device_private(dev); |
886 | | | 898 | |
887 | if (sc->sc_console_screen.scr_vd) { | | 899 | if (sc->sc_console_screen.scr_vd) { |
888 | if (sc->sc_ops.genfb_disable_polling) | | 900 | if (sc->sc_ops.genfb_disable_polling) |
889 | (*sc->sc_ops.genfb_disable_polling)(sc); | | 901 | (*sc->sc_ops.genfb_disable_polling)(sc); |
890 | vcons_disable_polling(&sc->vd); | | 902 | vcons_disable_polling(&sc->vd); |
891 | } | | 903 | } |
892 | } | | 904 | } |
| | | 905 | |
| | | 906 | #if GENFB_GLYPHCACHE > 0 |
| | | 907 | #define GLYPHCACHESIZE ((GENFB_GLYPHCACHE) * 1024 * 1024) |
| | | 908 | |
| | | 909 | static inline int |
| | | 910 | attr2idx(long attr) |
| | | 911 | { |
| | | 912 | if ((attr & 0xf0f00ff8) != 0) |
| | | 913 | return -1; |
| | | 914 | |
| | | 915 | return (((attr >> 16) & 0x0f) | ((attr >> 20) & 0xf0)); |
| | | 916 | } |
| | | 917 | |
| | | 918 | static int |
| | | 919 | genfb_setup_glyphcache(struct genfb_softc *sc, long defattr) |
| | | 920 | { |
| | | 921 | struct rasops_info *ri = &sc->sc_console_screen.scr_ri, |
| | | 922 | *cri = &sc->sc_cache_ri; |
| | | 923 | gc_bucket *b; |
| | | 924 | int i, usedcells = 0, idx, j; |
| | | 925 | |
| | | 926 | sc->sc_cache = kmem_alloc(GLYPHCACHESIZE, KM_SLEEP); |
| | | 927 | |
| | | 928 | /* |
| | | 929 | * now we build a mutant rasops_info for the cache - same pixel type |
| | | 930 | * and such as the real fb, but only one character per line for |
| | | 931 | * simplicity and locality |
| | | 932 | */ |
| | | 933 | memcpy(cri, ri, sizeof(struct rasops_info)); |
| | | 934 | cri->ri_ops.putchar = sc->sc_putchar; |
| | | 935 | cri->ri_width = ri->ri_font->fontwidth; |
| | | 936 | cri->ri_stride = ri->ri_xscale; |
| | | 937 | cri->ri_bits = sc->sc_cache; |
| | | 938 | cri->ri_hwbits = NULL; |
| | | 939 | cri->ri_origbits = sc->sc_cache; |
| | | 940 | cri->ri_cols = 1; |
| | | 941 | cri->ri_rows = GLYPHCACHESIZE / |
| | | 942 | (cri->ri_stride * cri->ri_font->fontheight); |
| | | 943 | cri->ri_xorigin = 0; |
| | | 944 | cri->ri_yorigin = 0; |
| | | 945 | cri->ri_xscale = ri->ri_xscale; |
| | | 946 | cri->ri_yscale = ri->ri_font->fontheight * ri->ri_xscale; |
| | | 947 | |
| | | 948 | printf("size %d %d %d\n", GLYPHCACHESIZE, ri->ri_width, ri->ri_stride); |
| | | 949 | printf("cells: %d\n", cri->ri_rows); |
| | | 950 | sc->sc_nbuckets = uimin(256, cri->ri_rows / 223); |
| | | 951 | sc->sc_buckets = kmem_alloc(sizeof(gc_bucket) * sc->sc_nbuckets, KM_SLEEP); |
| | | 952 | printf("buckets: %d\n", sc->sc_nbuckets); |
| | | 953 | for (i = 0; i < sc->sc_nbuckets; i++) { |
| | | 954 | b = &sc->sc_buckets[i]; |
| | | 955 | b->gb_firstcell = usedcells; |
| | | 956 | b->gb_numcells = uimin(223, cri->ri_rows - usedcells); |
| | | 957 | usedcells += 223; |
| | | 958 | b->gb_usedcells = 0; |
| | | 959 | b->gb_index = -1; |
| | | 960 | for (j = 0; j < 223; j++) b->gb_map[j] = -1; |
| | | 961 | } |
| | | 962 | |
| | | 963 | /* initialize the attribute map... */ |
| | | 964 | for (i = 0; i < 256; i++) { |
| | | 965 | sc->sc_attrmap[i] = -1; |
| | | 966 | } |
| | | 967 | |
| | | 968 | /* first bucket goes to default attr */ |
| | | 969 | idx = attr2idx(defattr); |
| | | 970 | printf("defattr %08lx idx %x\n", defattr, idx); |
| | | 971 | |
| | | 972 | if (idx >= 0) { |
| | | 973 | sc->sc_attrmap[idx] = 0; |
| | | 974 | sc->sc_buckets[0].gb_index = idx; |
| | | 975 | } |
| | | 976 | |
| | | 977 | return 0; |
| | | 978 | } |
| | | 979 | |
| | | 980 | static void |
| | | 981 | genfb_putchar(void *cookie, int row, int col, u_int c, long attr) |
| | | 982 | { |
| | | 983 | struct rasops_info *ri = cookie; |
| | | 984 | struct vcons_screen *scr = ri->ri_hw; |
| | | 985 | struct genfb_softc *sc = scr->scr_cookie; |
| | | 986 | uint8_t *src, *dst; |
| | | 987 | gc_bucket *b; |
| | | 988 | int i, idx, bi, cell; |
| | | 989 | |
| | | 990 | attr &= ~WSATTR_USERMASK; |
| | | 991 | |
| | | 992 | idx = attr2idx(attr); |
| | | 993 | if (c < 33 || c > 255 || idx < 0) goto nope; |
| | | 994 | |
| | | 995 | /* look for a bucket with the right attribute */ |
| | | 996 | bi = sc->sc_attrmap[idx]; |
| | | 997 | if (bi == -1) { |
| | | 998 | /* nope, see if there's an empty one left */ |
| | | 999 | bi = 1; |
| | | 1000 | while ((bi < sc->sc_nbuckets) && |
| | | 1001 | (sc->sc_buckets[bi].gb_index != -1)) { |
| | | 1002 | bi++; |
| | | 1003 | } |
| | | 1004 | if (bi < sc->sc_nbuckets) { |
| | | 1005 | /* found one -> grab it */ |
| | | 1006 | sc->sc_attrmap[idx] = bi; |
| | | 1007 | b = &sc->sc_buckets[bi]; |
| | | 1008 | b->gb_index = idx; |
| | | 1009 | b->gb_usedcells = 0; |
| | | 1010 | /* make sure this doesn't get evicted right away */ |
| | | 1011 | b->gb_lastread = time_uptime; |
| | | 1012 | } else { |
| | | 1013 | /* |
| | | 1014 | * still nothing |
| | | 1015 | * steal the least recently read bucket |
| | | 1016 | */ |
| | | 1017 | time_t moo = time_uptime; |
| | | 1018 | int oldest = 1; |
| | | 1019 | |
| | | 1020 | for (i = 1; i < sc->sc_nbuckets; i++) { |
| | | 1021 | if (sc->sc_buckets[i].gb_lastread < moo) { |
| | | 1022 | oldest = i; |
| | | 1023 | moo = sc->sc_buckets[i].gb_lastread; |
| | | 1024 | } |
| | | 1025 | } |
| | | 1026 | |
| | | 1027 | /* if we end up here all buckets must be in use */ |
| | | 1028 | b = &sc->sc_buckets[oldest]; |
| | | 1029 | sc->sc_attrmap[b->gb_index] = -1; |
| | | 1030 | b->gb_index = idx; |
| | | 1031 | b->gb_usedcells = 0; |
| | | 1032 | sc->sc_attrmap[idx] = oldest; |
| | | 1033 | /* now scrub it */ |
| | | 1034 | for (i = 0; i < 223; i++) |
| | | 1035 | b->gb_map[i] = -1; |
| | | 1036 | /* and set the time stamp */ |
| | | 1037 | b->gb_lastread = time_uptime; |
| | | 1038 | } |
| | | 1039 | } else { |
| | | 1040 | /* found one */ |
| | | 1041 | b = &sc->sc_buckets[bi]; |
| | | 1042 | } |
| | | 1043 | |
| | | 1044 | /* see if there's room in the bucket */ |
| | | 1045 | if (b->gb_usedcells >= b->gb_numcells) goto nope; |
| | | 1046 | |
| | | 1047 | cell = b->gb_map[c - 33]; |
| | | 1048 | if (cell == -1) { |
| | | 1049 | if (b->gb_usedcells >= b->gb_numcells) |
| | | 1050 | goto nope; |
| | | 1051 | cell = atomic_add_int_nv(&b->gb_usedcells, 1) - 1; |
| | | 1052 | b->gb_map[c - 33] = cell; |
| | | 1053 | cell += b->gb_firstcell; |
| | | 1054 | sc->sc_putchar(&sc->sc_cache_ri, cell, 0, c, attr); |
| | | 1055 | |
| | | 1056 | } else |
| | | 1057 | cell += b->gb_firstcell; |
| | | 1058 | |
| | | 1059 | src = sc->sc_cache + cell * sc->sc_cache_ri.ri_yscale; |
| | | 1060 | dst = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; |
| | | 1061 | for (i = 0; i < ri->ri_font->fontheight; i++) { |
| | | 1062 | memcpy(dst, src, ri->ri_xscale); |
| | | 1063 | src += ri->ri_xscale; |
| | | 1064 | dst += ri->ri_stride; |
| | | 1065 | } |
| | | 1066 | b->gb_lastread = time_uptime; |
| | | 1067 | return; |
| | | 1068 | nope: |
| | | 1069 | sc->sc_putchar(cookie, row, col, c, attr); |
| | | 1070 | } |
| | | 1071 | |
| | | 1072 | #endif |