blob: 1f93b1b85fa5e6b5952823226edfc1b4d50d6bb9 [file] [log] [blame]
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +03001// 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 Sankouski7fa964a2023-03-07 13:21:14 +030012#include <video_font.h>
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +030013#include "vidconsole_internal.h"
14
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +030015/**
16 * console_set_font() - prepare vidconsole for chosen font.
17 *
18 * @dev vidconsole device
19 * @fontdata pointer to font data struct
20 */
21static 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 Sankouskiaea2d2d2023-03-07 13:21:11 +030047int check_bpix_support(int bpix)
48{
Nikhil M Jain9e3301d2023-04-20 17:41:08 +053049 if (bpix == VIDEO_BPP8 && CONFIG_IS_ENABLED(VIDEO_BPP8))
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +030050 return 0;
Nikhil M Jain9e3301d2023-04-20 17:41:08 +053051 else if (bpix == VIDEO_BPP16 && CONFIG_IS_ENABLED(VIDEO_BPP16))
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +030052 return 0;
Nikhil M Jain9e3301d2023-04-20 17:41:08 +053053 else if (bpix == VIDEO_BPP32 && CONFIG_IS_ENABLED(VIDEO_BPP32))
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +030054 return 0;
55 else
56 return -ENOSYS;
57}
58
59inline 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
78int fill_char_vertically(uchar *pfont, void **line, struct video_priv *vid_priv,
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +030079 struct video_fontdata *fontdata, bool direction)
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +030080{
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +030081 int step, line_step, pbytes, bitcount, width_remainder, ret;
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +030082 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 Sankouski7fa964a2023-03-07 13:21:14 +030097 width_remainder = fontdata->width % 8;
98 for (int row = 0; row < fontdata->height; row++) {
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +030099 uchar bits;
100
101 bitcount = 8;
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300102 dst = *line;
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300103 for (int col = 0; col < fontdata->byte_width; col++) {
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300104 if (width_remainder) {
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300105 bool is_last_col = (fontdata->byte_width - col == 1);
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300106
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300107 if (is_last_col)
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300108 bitcount = width_remainder;
109 }
110 bits = pfont[col];
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300111
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300112 for (int bit = 0; bit < bitcount; bit++) {
113 u32 value = (bits & 0x80) ?
114 vid_priv->colour_fg :
115 vid_priv->colour_bg;
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300116
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300117 fill_pixel_and_goto_next(&dst,
118 value,
119 pbytes,
120 step
121 );
122 bits <<= 1;
123 }
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300124 }
125 *line += line_step;
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300126 pfont += fontdata->byte_width;
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300127 }
128 return ret;
129}
130
131int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_priv,
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300132 struct video_fontdata *fontdata, bool direction)
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300133{
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300134 int step, line_step, pbytes, bitcount = 8, width_remainder, ret;
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300135 void *dst;
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300136 u8 mask;
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300137
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 Sankouskiaea2d2d2023-03-07 13:21:11 +0300150
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300151 width_remainder = fontdata->width % 8;
152 for (int col = 0; col < fontdata->byte_width; col++) {
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300153 mask = 0x80;
154 if (width_remainder) {
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300155 bool is_last_col = (fontdata->byte_width - col == 1);
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300156
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300157 if (is_last_col)
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300158 bitcount = width_remainder;
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300159 }
Dzmitry Sankouski70d35a72023-03-07 13:21:12 +0300160 for (int bit = 0; bit < bitcount; bit++) {
161 dst = *line;
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300162 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 Sankouski70d35a72023-03-07 13:21:12 +0300165
166 fill_pixel_and_goto_next(&dst,
167 value,
168 pbytes,
169 step
170 );
171 }
172 *line += line_step;
173 mask >>= 1;
174 }
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300175 }
176 return ret;
177}
178
179int console_probe(struct udevice *dev)
180{
Dzmitry Sankouski7fa964a2023-03-07 13:21:14 +0300181 return console_set_font(dev, fonts);
Dzmitry Sankouskiaea2d2d2023-03-07 13:21:11 +0300182}
Dzmitry Sankouskibb165e42023-03-07 13:21:16 +0300183
184const 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
193int 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
200int console_simple_select_font(struct udevice *dev, const char *name, uint size)
201{
202 struct video_fontdata *font;
203
204 for (font = fonts; font->name; font++) {
205 if (!strcmp(name, font->name)) {
206 console_set_font(dev, font);
207 return 0;
208 }
209 };
210 printf("no such font: %s, make sure it's name has <width>x<height> format\n", name);
211 return -ENOENT;
212}