pi-linux/bsp/drivers/drm/kernel_panic_printf.c

281 lines
6.3 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright(c) 2020 - 2023 Allwinner Technology Co.,Ltd. All rights reserved. */
/*
* kernel_panic_printf/kernel_panic_printf.c
*
* Copyright (c) 2007-2023 Allwinnertech Co., Ltd.
* Author: zhengxiaobin <zhengxiaobin@allwinnertech.com>
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/fb.h>
#include <sunxi-log.h>
#include "error_img.h"
#include "fonts.h"
#include "sunxi_fbdev.h"
struct fb_info *sunxi_get_fb_info(int fb_id);
int sunxi_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
struct drm_fb_info *sunxi_get_drmfb_info(int fb_id);
int sunxi_drmfb_pan_display(struct drm_fb_info *info);
struct graphic_buffer {
int width;
int height;
unsigned char *buffer;
};
void draw_color(struct graphic_buffer *img, u32 color)
{
int offset = 0, i, j;
for (i = 0; i < img->height; i++)
for (j = 0; j < img->width; j++) {
unsigned int *p =
(unsigned int *)(img->buffer + offset);
*p = color;
offset += 4;
}
}
void draw_pixel(struct graphic_buffer *img, int x, int y, u32 color)
{
int offset = (img->width * y + x) * 4;
unsigned int *p = (unsigned int *)(img->buffer + offset);
*p = color;
}
void draw_img(struct graphic_buffer *img, int px, int py,
const unsigned char *raw, int w, int h)
{
int offset = 0, i = 0, j = 0;
u32 color;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
unsigned int r = raw[offset];
unsigned int g = raw[offset + 1];
unsigned int b = raw[offset + 2];
offset += 3;
color = ((int)0xff << 24) | (r << 16) | (g << 8) | b;
draw_pixel(img, px + j, py + i, color);
}
}
}
struct glyph_info *glyph_find(unsigned char t)
{
int i = 0;
struct glyph_info *glyph;
for (i = 0; i < character_list_size; i++) {
glyph = &character_list[i];
if (glyph->character == t)
return glyph;
}
return NULL;
}
void draw_glyph(struct graphic_buffer *img, int px, int py,
const struct glyph_info *info)
{
const unsigned char *glyph =
(const unsigned char *)font_glyph_bitmap + info->offset;
int i = 0, j = 0;
for (i = 0; i < info->h; i++) {
for (j = 0; j < info->w; j++) {
u32 color = glyph[i * info->w + j];
color = ((color & 0xff) << 16) | (color & 0xff00) | ((color & 0xff0000) >> 16);
draw_pixel(img, px + j, py + i, color | 0xff000000);
}
}
}
void glyph_reander_string(char *str, int px, int *py, struct graphic_buffer *img)
{
int i = 0;
unsigned char t;
struct glyph_info *glyph;
int origin_px = px, line_height = 0;
line_height = character_font_size * 3 / 2;
for (i = 0; i < strlen(str); i++) {
t = str[i];
if (px + character_font_size > img->width) {
*py += line_height;
px = origin_px;
--i;
if (*py > img->height)
break;
continue;
}
if (*py + line_height > img->height)
break;
if (t == ' ') {
px += (character_font_size / 2);
continue;
}
glyph = glyph_find(t);
if (glyph) {
px += glyph->bitmap_left;
draw_glyph(img, px, *py - glyph->bitmap_top, glyph);
px += (glyph->w + 1);
}
}
*py += line_height;
}
#if IS_ENABLED (CONFIG_FB)
static void sunxi_fbdev_printf(char *string)
{
struct fb_info *p_info = NULL;
struct graphic_buffer img;
int px, py, i = 0, j = 0;
char temp[81] = {0};
p_info = sunxi_get_fb_info(0);
if (!p_info) {
printk(KERN_ERR "Null fb info\n");
goto err_free;
}
img.width = p_info->var.xres;
img.height = p_info->var.yres;
img.buffer = p_info->screen_base;
if (!img.buffer) {
printk(KERN_ERR "NULL fb buffer\n");
goto err_free;
}
draw_color(&img, 0xff000000);
px = crashdump_raw_width + 64;
py = img.height / 2;
draw_img(&img, 32, py - 2 * character_font_size, crashdump_img_raw,
crashdump_raw_width, crashdump_raw_height);
i = 0;
j = 0;
while (string[i] != '\0') {
if (string[i] == '\n') {
temp[j] = '\0';
glyph_reander_string(temp, px, &py, &img);
j = 0;
} else {
temp[j] = string[i];
++j;
if (j == 80) {
temp[j] = '\0';
j = 0;
glyph_reander_string(temp, px, &py, &img);
}
}
++i;
}
temp[j] = '\0';
glyph_reander_string(temp, px, &py, &img);
p_info->var.reserved[0] = FB_ACTIVATE_FORCE;
//platform_swap_rb_order(p_info, true);
sunxi_fb_pan_display(&p_info->var, p_info);
err_free:
return ;
}
#else
static void sunxi_drmfb_printf(char *string)
{
struct drm_fb_info *p_info = NULL;
struct graphic_buffer img;
int px, py, i = 0, j = 0;
char temp[81] = {0};
p_info = sunxi_get_drmfb_info(0);
if (!p_info) {
printk(KERN_ERR "Null fb info\n");
goto err_free;
}
img.width = p_info->xres;
img.height = p_info->yres;
img.buffer = p_info->screen_base;
if (!img.buffer) {
printk(KERN_ERR "NULL fb buffer\n");
goto err_free;
}
draw_color(&img, 0xff000000);
px = crashdump_raw_width + 64;
py = img.height / 2;
draw_img(&img, 32, py - 2 * character_font_size, crashdump_img_raw,
crashdump_raw_width, crashdump_raw_height);
i = 0;
j = 0;
while (string[i] != '\0') {
if (string[i] == '\n') {
temp[j] = '\0';
glyph_reander_string(temp, px, &py, &img);
j = 0;
} else {
temp[j] = string[i];
++j;
if (j == 80) {
temp[j] = '\0';
j = 0;
glyph_reander_string(temp, px, &py, &img);
}
}
++i;
}
temp[j] = '\0';
glyph_reander_string(temp, px, &py, &img);
p_info->reserved[0] = FB_ACTIVATE_FORCE;
//platform_swap_rb_order(p_info, true);
sunxi_drmfb_pan_display(p_info);
err_free:
return ;
}
#endif
void sunxi_kernel_panic_printf(const char *str, ...)
{
int i = 0;
char *string = NULL;
va_list args;
if (!str || !strlen(str)) {
printk(KERN_ERR "Null string\n");
return;
}
string = kzalloc(512, GFP_KERNEL);
if (!string)
printk(KERN_ERR "String malloc err\n");
va_start(args, str);
i = vsnprintf(string, 512, str, args);
va_end(args);
if (i > 512 || i == 0) {
printk(KERN_ERR "Out of string length\n");
goto err_free;
}
#if IS_ENABLED (CONFIG_FB)
sunxi_fbdev_printf(string);
#else
sunxi_drmfb_printf(string);
#endif
err_free:
kfree(string);
return ;
}
EXPORT_SYMBOL_GPL(sunxi_kernel_panic_printf);
// End of File