2023-03-07 10:21:11 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2015 Google, Inc
|
|
|
|
* (C) Copyright 2015
|
|
|
|
* Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
|
|
|
|
* (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <video.h>
|
|
|
|
#include <video_console.h>
|
|
|
|
#include <dm.h>
|
2023-03-07 10:21:14 +00:00
|
|
|
#include <video_font.h>
|
2023-03-07 10:21:11 +00:00
|
|
|
#include "vidconsole_internal.h"
|
|
|
|
|
2023-03-07 10:21:14 +00:00
|
|
|
/**
|
|
|
|
* console_set_font() - prepare vidconsole for chosen font.
|
|
|
|
*
|
|
|
|
* @dev vidconsole device
|
|
|
|
* @fontdata pointer to font data struct
|
|
|
|
*/
|
|
|
|
static int console_set_font(struct udevice *dev, struct video_fontdata *fontdata)
|
|
|
|
{
|
|
|
|
struct console_simple_priv *priv = dev_get_priv(dev);
|
|
|
|
struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
|
|
|
|
struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
|
|
|
|
|
|
|
|
debug("console_simple: setting %s font\n", fontdata->name);
|
|
|
|
debug("width: %d\n", fontdata->width);
|
|
|
|
debug("byte width: %d\n", fontdata->byte_width);
|
|
|
|
debug("height: %d\n", fontdata->height);
|
|
|
|
|
|
|
|
priv->fontdata = fontdata;
|
|
|
|
vc_priv->x_charsize = fontdata->width;
|
|
|
|
vc_priv->y_charsize = fontdata->height;
|
|
|
|
if (vid_priv->rot % 2) {
|
|
|
|
vc_priv->cols = vid_priv->ysize / fontdata->width;
|
|
|
|
vc_priv->rows = vid_priv->xsize / fontdata->height;
|
|
|
|
vc_priv->xsize_frac = VID_TO_POS(vid_priv->ysize);
|
|
|
|
} else {
|
|
|
|
vc_priv->cols = vid_priv->xsize / fontdata->width;
|
|
|
|
vc_priv->rows = vid_priv->ysize / fontdata->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-03-07 10:21:11 +00:00
|
|
|
int check_bpix_support(int bpix)
|
|
|
|
{
|
2023-04-20 12:11:08 +00:00
|
|
|
if (bpix == VIDEO_BPP8 && CONFIG_IS_ENABLED(VIDEO_BPP8))
|
2023-03-07 10:21:11 +00:00
|
|
|
return 0;
|
2023-04-20 12:11:08 +00:00
|
|
|
else if (bpix == VIDEO_BPP16 && CONFIG_IS_ENABLED(VIDEO_BPP16))
|
2023-03-07 10:21:11 +00:00
|
|
|
return 0;
|
2023-04-20 12:11:08 +00:00
|
|
|
else if (bpix == VIDEO_BPP32 && CONFIG_IS_ENABLED(VIDEO_BPP32))
|
2023-03-07 10:21:11 +00:00
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void fill_pixel_and_goto_next(void **dstp, u32 value, int pbytes, int step)
|
|
|
|
{
|
|
|
|
u8 *dst_byte = *dstp;
|
|
|
|
|
|
|
|
if (pbytes == 4) {
|
|
|
|
u32 *dst = *dstp;
|
|
|
|
*dst = value;
|
|
|
|
}
|
|
|
|
if (pbytes == 2) {
|
|
|
|
u16 *dst = *dstp;
|
|
|
|
*dst = value;
|
|
|
|
}
|
|
|
|
if (pbytes == 1) {
|
|
|
|
u8 *dst = *dstp;
|
|
|
|
*dst = value;
|
|
|
|
}
|
|
|
|
*dstp = dst_byte + step;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fill_char_vertically(uchar *pfont, void **line, struct video_priv *vid_priv,
|
2023-03-07 10:21:14 +00:00
|
|
|
struct video_fontdata *fontdata, bool direction)
|
2023-03-07 10:21:11 +00:00
|
|
|
{
|
2023-03-07 10:21:12 +00:00
|
|
|
int step, line_step, pbytes, bitcount, width_remainder, ret;
|
2023-03-07 10:21:11 +00:00
|
|
|
void *dst;
|
|
|
|
|
|
|
|
ret = check_bpix_support(vid_priv->bpix);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
pbytes = VNBYTES(vid_priv->bpix);
|
|
|
|
if (direction) {
|
|
|
|
step = -pbytes;
|
|
|
|
line_step = -vid_priv->line_length;
|
|
|
|
} else {
|
|
|
|
step = pbytes;
|
|
|
|
line_step = vid_priv->line_length;
|
|
|
|
}
|
|
|
|
|
2023-03-07 10:21:14 +00:00
|
|
|
width_remainder = fontdata->width % 8;
|
|
|
|
for (int row = 0; row < fontdata->height; row++) {
|
2023-03-07 10:21:12 +00:00
|
|
|
uchar bits;
|
|
|
|
|
|
|
|
bitcount = 8;
|
2023-03-07 10:21:11 +00:00
|
|
|
dst = *line;
|
2023-03-07 10:21:14 +00:00
|
|
|
for (int col = 0; col < fontdata->byte_width; col++) {
|
2023-03-07 10:21:12 +00:00
|
|
|
if (width_remainder) {
|
2023-03-07 10:21:14 +00:00
|
|
|
bool is_last_col = (fontdata->byte_width - col == 1);
|
2023-03-07 10:21:12 +00:00
|
|
|
|
2023-03-07 10:21:14 +00:00
|
|
|
if (is_last_col)
|
2023-03-07 10:21:12 +00:00
|
|
|
bitcount = width_remainder;
|
|
|
|
}
|
|
|
|
bits = pfont[col];
|
|
|
|
|
|
|
|
for (int bit = 0; bit < bitcount; bit++) {
|
|
|
|
u32 value = (bits & 0x80) ?
|
|
|
|
vid_priv->colour_fg :
|
|
|
|
vid_priv->colour_bg;
|
|
|
|
|
|
|
|
fill_pixel_and_goto_next(&dst,
|
|
|
|
value,
|
|
|
|
pbytes,
|
|
|
|
step
|
|
|
|
);
|
|
|
|
bits <<= 1;
|
|
|
|
}
|
2023-03-07 10:21:11 +00:00
|
|
|
}
|
|
|
|
*line += line_step;
|
2023-03-07 10:21:14 +00:00
|
|
|
pfont += fontdata->byte_width;
|
2023-03-07 10:21:11 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_priv,
|
2023-03-07 10:21:14 +00:00
|
|
|
struct video_fontdata *fontdata, bool direction)
|
2023-03-07 10:21:11 +00:00
|
|
|
{
|
2023-03-07 10:21:12 +00:00
|
|
|
int step, line_step, pbytes, bitcount = 8, width_remainder, ret;
|
2023-03-07 10:21:11 +00:00
|
|
|
void *dst;
|
2023-03-07 10:21:12 +00:00
|
|
|
u8 mask;
|
2023-03-07 10:21:11 +00:00
|
|
|
|
|
|
|
ret = check_bpix_support(vid_priv->bpix);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
pbytes = VNBYTES(vid_priv->bpix);
|
|
|
|
if (direction) {
|
|
|
|
step = -pbytes;
|
|
|
|
line_step = vid_priv->line_length;
|
|
|
|
} else {
|
|
|
|
step = pbytes;
|
|
|
|
line_step = -vid_priv->line_length;
|
|
|
|
}
|
2023-03-07 10:21:12 +00:00
|
|
|
|
2023-03-07 10:21:14 +00:00
|
|
|
width_remainder = fontdata->width % 8;
|
|
|
|
for (int col = 0; col < fontdata->byte_width; col++) {
|
2023-03-07 10:21:12 +00:00
|
|
|
mask = 0x80;
|
|
|
|
if (width_remainder) {
|
2023-03-07 10:21:14 +00:00
|
|
|
bool is_last_col = (fontdata->byte_width - col == 1);
|
2023-03-07 10:21:12 +00:00
|
|
|
|
2023-03-07 10:21:14 +00:00
|
|
|
if (is_last_col)
|
2023-03-07 10:21:12 +00:00
|
|
|
bitcount = width_remainder;
|
|
|
|
}
|
|
|
|
for (int bit = 0; bit < bitcount; bit++) {
|
|
|
|
dst = *line;
|
2023-03-07 10:21:14 +00:00
|
|
|
for (int row = 0; row < fontdata->height; row++) {
|
|
|
|
u32 value = (pfont[row * fontdata->byte_width + col]
|
|
|
|
& mask) ? vid_priv->colour_fg : vid_priv->colour_bg;
|
2023-03-07 10:21:12 +00:00
|
|
|
|
|
|
|
fill_pixel_and_goto_next(&dst,
|
|
|
|
value,
|
|
|
|
pbytes,
|
|
|
|
step
|
|
|
|
);
|
|
|
|
}
|
|
|
|
*line += line_step;
|
|
|
|
mask >>= 1;
|
2023-03-07 10:21:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int console_probe(struct udevice *dev)
|
|
|
|
{
|
2023-03-07 10:21:14 +00:00
|
|
|
return console_set_font(dev, fonts);
|
2023-03-07 10:21:11 +00:00
|
|
|
}
|
2023-03-07 10:21:16 +00:00
|
|
|
|
|
|
|
const char *console_simple_get_font_size(struct udevice *dev, uint *sizep)
|
|
|
|
{
|
|
|
|
struct console_simple_priv *priv = dev_get_priv(dev);
|
|
|
|
|
|
|
|
*sizep = priv->fontdata->width;
|
|
|
|
|
|
|
|
return priv->fontdata->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
int console_simple_get_font(struct udevice *dev, int seq, struct vidfont_info *info)
|
|
|
|
{
|
|
|
|
info->name = fonts[seq].name;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int console_simple_select_font(struct udevice *dev, const char *name, uint size)
|
|
|
|
{
|
|
|
|
struct video_fontdata *font;
|
|
|
|
|
2023-05-25 12:17:15 +00:00
|
|
|
if (!name) {
|
|
|
|
if (fonts->name)
|
|
|
|
console_set_font(dev, fonts);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-03-07 10:21:16 +00:00
|
|
|
for (font = fonts; font->name; font++) {
|
|
|
|
if (!strcmp(name, font->name)) {
|
|
|
|
console_set_font(dev, font);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
printf("no such font: %s, make sure it's name has <width>x<height> format\n", name);
|
|
|
|
return -ENOENT;
|
|
|
|
}
|