Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Copyright (c) 2015 Google, Inc |
| 4 | * (C) Copyright 2015 |
| 5 | * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com |
| 6 | * (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com> |
| 7 | */ |
| 8 | |
| 9 | #include <video.h> |
| 10 | #include <video_console.h> |
| 11 | #include <dm.h> |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 12 | #include <video_font.h> |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 13 | #include "vidconsole_internal.h" |
| 14 | |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 15 | /** |
| 16 | * console_set_font() - prepare vidconsole for chosen font. |
| 17 | * |
| 18 | * @dev vidconsole device |
| 19 | * @fontdata pointer to font data struct |
| 20 | */ |
| 21 | static int console_set_font(struct udevice *dev, struct video_fontdata *fontdata) |
| 22 | { |
| 23 | struct console_simple_priv *priv = dev_get_priv(dev); |
| 24 | struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); |
| 25 | struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); |
| 26 | |
| 27 | debug("console_simple: setting %s font\n", fontdata->name); |
| 28 | debug("width: %d\n", fontdata->width); |
| 29 | debug("byte width: %d\n", fontdata->byte_width); |
| 30 | debug("height: %d\n", fontdata->height); |
| 31 | |
| 32 | priv->fontdata = fontdata; |
| 33 | vc_priv->x_charsize = fontdata->width; |
| 34 | vc_priv->y_charsize = fontdata->height; |
| 35 | if (vid_priv->rot % 2) { |
| 36 | vc_priv->cols = vid_priv->ysize / fontdata->width; |
| 37 | vc_priv->rows = vid_priv->xsize / fontdata->height; |
| 38 | vc_priv->xsize_frac = VID_TO_POS(vid_priv->ysize); |
| 39 | } else { |
| 40 | vc_priv->cols = vid_priv->xsize / fontdata->width; |
| 41 | vc_priv->rows = vid_priv->ysize / fontdata->height; |
| 42 | } |
| 43 | |
| 44 | return 0; |
| 45 | } |
| 46 | |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 47 | int check_bpix_support(int bpix) |
| 48 | { |
Nikhil M Jain | 9e3301d | 2023-04-20 17:41:08 +0530 | [diff] [blame] | 49 | if (bpix == VIDEO_BPP8 && CONFIG_IS_ENABLED(VIDEO_BPP8)) |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 50 | return 0; |
Nikhil M Jain | 9e3301d | 2023-04-20 17:41:08 +0530 | [diff] [blame] | 51 | else if (bpix == VIDEO_BPP16 && CONFIG_IS_ENABLED(VIDEO_BPP16)) |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 52 | return 0; |
Nikhil M Jain | 9e3301d | 2023-04-20 17:41:08 +0530 | [diff] [blame] | 53 | else if (bpix == VIDEO_BPP32 && CONFIG_IS_ENABLED(VIDEO_BPP32)) |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 54 | return 0; |
| 55 | else |
| 56 | return -ENOSYS; |
| 57 | } |
| 58 | |
| 59 | inline void fill_pixel_and_goto_next(void **dstp, u32 value, int pbytes, int step) |
| 60 | { |
| 61 | u8 *dst_byte = *dstp; |
| 62 | |
| 63 | if (pbytes == 4) { |
| 64 | u32 *dst = *dstp; |
| 65 | *dst = value; |
| 66 | } |
| 67 | if (pbytes == 2) { |
| 68 | u16 *dst = *dstp; |
| 69 | *dst = value; |
| 70 | } |
| 71 | if (pbytes == 1) { |
| 72 | u8 *dst = *dstp; |
| 73 | *dst = value; |
| 74 | } |
| 75 | *dstp = dst_byte + step; |
| 76 | } |
| 77 | |
| 78 | int fill_char_vertically(uchar *pfont, void **line, struct video_priv *vid_priv, |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 79 | struct video_fontdata *fontdata, bool direction) |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 80 | { |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 81 | int step, line_step, pbytes, bitcount, width_remainder, ret; |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 82 | void *dst; |
| 83 | |
| 84 | ret = check_bpix_support(vid_priv->bpix); |
| 85 | if (ret) |
| 86 | return ret; |
| 87 | |
| 88 | pbytes = VNBYTES(vid_priv->bpix); |
| 89 | if (direction) { |
| 90 | step = -pbytes; |
| 91 | line_step = -vid_priv->line_length; |
| 92 | } else { |
| 93 | step = pbytes; |
| 94 | line_step = vid_priv->line_length; |
| 95 | } |
| 96 | |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 97 | width_remainder = fontdata->width % 8; |
| 98 | for (int row = 0; row < fontdata->height; row++) { |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 99 | uchar bits; |
| 100 | |
| 101 | bitcount = 8; |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 102 | dst = *line; |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 103 | for (int col = 0; col < fontdata->byte_width; col++) { |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 104 | if (width_remainder) { |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 105 | bool is_last_col = (fontdata->byte_width - col == 1); |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 106 | |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 107 | if (is_last_col) |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 108 | bitcount = width_remainder; |
| 109 | } |
| 110 | bits = pfont[col]; |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 111 | |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 112 | for (int bit = 0; bit < bitcount; bit++) { |
| 113 | u32 value = (bits & 0x80) ? |
| 114 | vid_priv->colour_fg : |
| 115 | vid_priv->colour_bg; |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 116 | |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 117 | fill_pixel_and_goto_next(&dst, |
| 118 | value, |
| 119 | pbytes, |
| 120 | step |
| 121 | ); |
| 122 | bits <<= 1; |
| 123 | } |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 124 | } |
| 125 | *line += line_step; |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 126 | pfont += fontdata->byte_width; |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 127 | } |
| 128 | return ret; |
| 129 | } |
| 130 | |
| 131 | int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_priv, |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 132 | struct video_fontdata *fontdata, bool direction) |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 133 | { |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 134 | int step, line_step, pbytes, bitcount = 8, width_remainder, ret; |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 135 | void *dst; |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 136 | u8 mask; |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 137 | |
| 138 | ret = check_bpix_support(vid_priv->bpix); |
| 139 | if (ret) |
| 140 | return ret; |
| 141 | |
| 142 | pbytes = VNBYTES(vid_priv->bpix); |
| 143 | if (direction) { |
| 144 | step = -pbytes; |
| 145 | line_step = vid_priv->line_length; |
| 146 | } else { |
| 147 | step = pbytes; |
| 148 | line_step = -vid_priv->line_length; |
| 149 | } |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 150 | |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 151 | width_remainder = fontdata->width % 8; |
| 152 | for (int col = 0; col < fontdata->byte_width; col++) { |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 153 | mask = 0x80; |
| 154 | if (width_remainder) { |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 155 | bool is_last_col = (fontdata->byte_width - col == 1); |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 156 | |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 157 | if (is_last_col) |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 158 | bitcount = width_remainder; |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 159 | } |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 160 | for (int bit = 0; bit < bitcount; bit++) { |
| 161 | dst = *line; |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 162 | for (int row = 0; row < fontdata->height; row++) { |
| 163 | u32 value = (pfont[row * fontdata->byte_width + col] |
| 164 | & mask) ? vid_priv->colour_fg : vid_priv->colour_bg; |
Dzmitry Sankouski | 70d35a7 | 2023-03-07 13:21:12 +0300 | [diff] [blame] | 165 | |
| 166 | fill_pixel_and_goto_next(&dst, |
| 167 | value, |
| 168 | pbytes, |
| 169 | step |
| 170 | ); |
| 171 | } |
| 172 | *line += line_step; |
| 173 | mask >>= 1; |
| 174 | } |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 175 | } |
| 176 | return ret; |
| 177 | } |
| 178 | |
Simon Glass | 377f79aa | 2023-10-01 19:13:21 -0600 | [diff] [blame] | 179 | int draw_cursor_vertically(void **line, struct video_priv *vid_priv, |
| 180 | uint height, bool direction) |
| 181 | { |
| 182 | int step, line_step, pbytes, ret; |
| 183 | uint value; |
| 184 | void *dst; |
| 185 | |
| 186 | ret = check_bpix_support(vid_priv->bpix); |
| 187 | if (ret) |
| 188 | return ret; |
| 189 | |
| 190 | pbytes = VNBYTES(vid_priv->bpix); |
| 191 | if (direction) { |
| 192 | step = -pbytes; |
| 193 | line_step = -vid_priv->line_length; |
| 194 | } else { |
| 195 | step = pbytes; |
| 196 | line_step = vid_priv->line_length; |
| 197 | } |
| 198 | |
| 199 | value = vid_priv->colour_fg; |
| 200 | |
| 201 | for (int row = 0; row < height; row++) { |
| 202 | dst = *line; |
| 203 | for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++) |
| 204 | fill_pixel_and_goto_next(&dst, value, pbytes, step); |
| 205 | *line += line_step; |
| 206 | } |
| 207 | return ret; |
| 208 | } |
| 209 | |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 210 | int console_probe(struct udevice *dev) |
| 211 | { |
Dzmitry Sankouski | 7fa964a | 2023-03-07 13:21:14 +0300 | [diff] [blame] | 212 | return console_set_font(dev, fonts); |
Dzmitry Sankouski | aea2d2d | 2023-03-07 13:21:11 +0300 | [diff] [blame] | 213 | } |
Dzmitry Sankouski | bb165e4 | 2023-03-07 13:21:16 +0300 | [diff] [blame] | 214 | |
| 215 | const char *console_simple_get_font_size(struct udevice *dev, uint *sizep) |
| 216 | { |
| 217 | struct console_simple_priv *priv = dev_get_priv(dev); |
| 218 | |
| 219 | *sizep = priv->fontdata->width; |
| 220 | |
| 221 | return priv->fontdata->name; |
| 222 | } |
| 223 | |
| 224 | int console_simple_get_font(struct udevice *dev, int seq, struct vidfont_info *info) |
| 225 | { |
| 226 | info->name = fonts[seq].name; |
| 227 | |
Janne Grunau | bb7c720 | 2024-01-17 23:29:29 +0100 | [diff] [blame] | 228 | return info->name ? 0 : -ENOENT; |
Dzmitry Sankouski | bb165e4 | 2023-03-07 13:21:16 +0300 | [diff] [blame] | 229 | } |
| 230 | |
| 231 | int console_simple_select_font(struct udevice *dev, const char *name, uint size) |
| 232 | { |
| 233 | struct video_fontdata *font; |
| 234 | |
Ondrej Jirman | 7c5281f | 2023-05-25 14:17:15 +0200 | [diff] [blame] | 235 | if (!name) { |
| 236 | if (fonts->name) |
| 237 | console_set_font(dev, fonts); |
| 238 | return 0; |
| 239 | } |
| 240 | |
Dzmitry Sankouski | bb165e4 | 2023-03-07 13:21:16 +0300 | [diff] [blame] | 241 | for (font = fonts; font->name; font++) { |
| 242 | if (!strcmp(name, font->name)) { |
| 243 | console_set_font(dev, font); |
| 244 | return 0; |
| 245 | } |
| 246 | }; |
| 247 | printf("no such font: %s, make sure it's name has <width>x<height> format\n", name); |
| 248 | return -ENOENT; |
| 249 | } |