Prepare v2023.10
[platform/kernel/u-boot.git] / drivers / video / console_core.c
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>
12 #include <video_font.h>
13 #include "vidconsole_internal.h"
14
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
47 int check_bpix_support(int bpix)
48 {
49         if (bpix == VIDEO_BPP8 && CONFIG_IS_ENABLED(VIDEO_BPP8))
50                 return 0;
51         else if (bpix == VIDEO_BPP16 && CONFIG_IS_ENABLED(VIDEO_BPP16))
52                 return 0;
53         else if (bpix == VIDEO_BPP32 && CONFIG_IS_ENABLED(VIDEO_BPP32))
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,
79                          struct video_fontdata *fontdata, bool direction)
80 {
81         int step, line_step, pbytes, bitcount, width_remainder, ret;
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
97         width_remainder = fontdata->width % 8;
98         for (int row = 0; row < fontdata->height; row++) {
99                 uchar bits;
100
101                 bitcount = 8;
102                 dst = *line;
103                 for (int col = 0; col < fontdata->byte_width; col++) {
104                         if (width_remainder) {
105                                 bool is_last_col = (fontdata->byte_width - col == 1);
106
107                                 if (is_last_col)
108                                         bitcount = width_remainder;
109                         }
110                         bits = pfont[col];
111
112                         for (int bit = 0; bit < bitcount; bit++) {
113                                 u32 value = (bits & 0x80) ?
114                                         vid_priv->colour_fg :
115                                         vid_priv->colour_bg;
116
117                                 fill_pixel_and_goto_next(&dst,
118                                                          value,
119                                                          pbytes,
120                                                          step
121                                 );
122                                 bits <<= 1;
123                         }
124                 }
125                 *line += line_step;
126                 pfont += fontdata->byte_width;
127         }
128         return ret;
129 }
130
131 int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_priv,
132                            struct video_fontdata *fontdata, bool direction)
133 {
134         int step, line_step, pbytes, bitcount = 8, width_remainder, ret;
135         void *dst;
136         u8 mask;
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         }
150
151         width_remainder = fontdata->width % 8;
152         for (int col = 0; col < fontdata->byte_width; col++) {
153                 mask = 0x80;
154                 if (width_remainder) {
155                         bool is_last_col = (fontdata->byte_width - col == 1);
156
157                         if (is_last_col)
158                                 bitcount = width_remainder;
159                 }
160                 for (int bit = 0; bit < bitcount; bit++) {
161                         dst = *line;
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;
165
166                                 fill_pixel_and_goto_next(&dst,
167                                                          value,
168                                                          pbytes,
169                                                          step
170                                 );
171                         }
172                         *line += line_step;
173                         mask >>= 1;
174                 }
175         }
176         return ret;
177 }
178
179 int console_probe(struct udevice *dev)
180 {
181         return console_set_font(dev, fonts);
182 }
183
184 const char *console_simple_get_font_size(struct udevice *dev, uint *sizep)
185 {
186         struct console_simple_priv *priv = dev_get_priv(dev);
187
188         *sizep = priv->fontdata->width;
189
190         return priv->fontdata->name;
191 }
192
193 int console_simple_get_font(struct udevice *dev, int seq, struct vidfont_info *info)
194 {
195         info->name = fonts[seq].name;
196
197         return 0;
198 }
199
200 int console_simple_select_font(struct udevice *dev, const char *name, uint size)
201 {
202         struct video_fontdata *font;
203
204         if (!name) {
205                 if (fonts->name)
206                         console_set_font(dev, fonts);
207                 return 0;
208         }
209
210         for (font = fonts; font->name; font++) {
211                 if (!strcmp(name, font->name)) {
212                         console_set_font(dev, font);
213                         return 0;
214                 }
215         };
216         printf("no such font: %s, make sure it's name has <width>x<height> format\n", name);
217         return -ENOENT;
218 }