pinephone-nuttx/render.zig

508 lines
21 KiB
Zig
Raw Normal View History

2022-10-31 11:56:43 +08:00
//***************************************************************************
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership. The
// ASF licenses this file to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance with the
// License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
//***************************************************************************
2022-10-31 12:12:26 +08:00
//! PinePhone Display Engine Driver for Apache NuttX RTOS.
2022-10-31 12:04:05 +08:00
//! This Framebuffer Interface is compatible with NuttX Framebuffers:
//! https://github.com/lupyuen/incubator-nuttx/blob/master/include/nuttx/video/fb.h
2022-10-31 11:56:43 +08:00
/// Import the Zig Standard Library
const std = @import("std");
2022-10-31 12:12:26 +08:00
/// Import the MIPI Display Serial Interface Module
const dsi = @import("./display.zig");
2022-11-01 20:53:09 +08:00
/// Import NuttX Functions from C
2022-10-31 11:56:43 +08:00
const c = @cImport({
// NuttX Defines
@cDefine("__NuttX__", "");
@cDefine("NDEBUG", "");
@cDefine("FAR", "");
// NuttX Framebuffer Defines
@cDefine("CONFIG_FB_OVERLAY", "");
// NuttX Header Files
@cInclude("arch/types.h");
@cInclude("../../nuttx/include/limits.h");
@cInclude("nuttx/config.h");
@cInclude("inttypes.h");
@cInclude("unistd.h");
@cInclude("stdlib.h");
@cInclude("stdio.h");
// NuttX Framebuffer Header Files
@cInclude("nuttx/video/fb.h");
});
2022-10-31 12:18:57 +08:00
/// Render a Test Pattern on PinePhone's Display.
/// Calls Allwinner A64 Display Engine, Timing Controller and MIPI Display Serial Interface.
2022-10-31 17:08:08 +08:00
/// See https://lupyuen.github.io/articles/de#appendix-programming-the-allwinner-a64-display-engine
2022-10-31 11:56:43 +08:00
pub export fn test_render() void {
2022-10-31 16:47:32 +08:00
debug("test_render", .{});
2022-10-31 14:25:41 +08:00
// Validate the Framebuffer Sizes at Compile Time
comptime {
assert(planeInfo.xres_virtual == videoInfo.xres);
assert(planeInfo.yres_virtual == videoInfo.yres);
assert(planeInfo.fblen == planeInfo.xres_virtual * planeInfo.yres_virtual * 4);
assert(planeInfo.stride == planeInfo.xres_virtual * 4);
assert(overlayInfo[0].fblen == @intCast(usize, overlayInfo[0].sarea.w) * overlayInfo[0].sarea.h * 4);
assert(overlayInfo[0].stride == overlayInfo[0].sarea.w * 4);
assert(overlayInfo[1].fblen == @intCast(usize, overlayInfo[1].sarea.w) * overlayInfo[1].sarea.h * 4);
assert(overlayInfo[1].stride == overlayInfo[1].sarea.w * 4);
}
2022-10-31 14:34:21 +08:00
2022-11-01 20:51:52 +08:00
// TODO: Init PinePhone's Allwinner A64 Timing Controller TCON0 (tcon0_init)
2022-11-01 19:58:50 +08:00
// https://gist.github.com/lupyuen/c12f64cf03d3a81e9c69f9fef49d9b70#tcon0_init
2022-11-01 20:51:52 +08:00
// TODO: Init PinePhone's Allwinner A64 MIPI Display Serial Interface (dsi_init)
2022-11-01 19:58:50 +08:00
// Call https://gist.github.com/lupyuen/c12f64cf03d3a81e9c69f9fef49d9b70#dsi_init
2022-11-01 20:51:52 +08:00
// TODO: Init PinePhone's Allwinner A64 Display Engine (de2_init)
2022-11-01 19:58:50 +08:00
// https://gist.github.com/lupyuen/c12f64cf03d3a81e9c69f9fef49d9b70#de2_init
2022-11-01 20:51:52 +08:00
// TODO: Turn on PinePhone's Backlight (backlight_enable)
2022-11-01 19:58:50 +08:00
// https://gist.github.com/lupyuen/c12f64cf03d3a81e9c69f9fef49d9b70#backlight_enable
2022-11-01 13:43:18 +08:00
// Init Framebuffer 0:
// Fill with Blue, Green and Red
var i: usize = 0;
while (i < fb0.len) : (i += 1) {
// Colours are in XRGB 8888 format
if (i < fb0.len / 4) {
// Blue for top quarter
fb0[i] = 0x80000080;
} else if (i < fb0.len / 2) {
// Green for next quarter
fb0[i] = 0x80008000;
} else {
// Red for lower half
fb0[i] = 0x80800000;
}
}
// Init Framebuffer 1:
// Fill with Semi-Transparent Blue
i = 0;
while (i < fb1.len) : (i += 1) {
// Colours are in ARGB 8888 format
fb1[i] = 0x80000080;
}
// Init Framebuffer 2:
// Fill with Semi-Transparent Green Circle
var y: usize = 0;
while (y < 1440) : (y += 1) {
var x: usize = 0;
while (x < 720) : (x += 1) {
// Get pixel index
const p = (y * 720) + x;
assert(p < fb2.len);
// Shift coordinates so that centre of screen is (0,0)
2022-11-01 13:49:13 +08:00
const x_shift = @intCast(isize, x) - 360;
const y_shift = @intCast(isize, y) - 720;
2022-11-01 13:43:18 +08:00
// If x^2 + y^2 < radius^2, set the pixel to Semi-Transparent Green
if (x_shift*x_shift + y_shift*y_shift < 360*360) {
fb2[p] = 0x80008000; // Semi-Transparent Green in ARGB 8888 Format
} else { // Otherwise set to Transparent Black
fb2[p] = 0x00000000; // Transparent Black in ARGB 8888 Format
}
}
}
2022-10-31 16:40:59 +08:00
// Init the UI Blender for PinePhone's A64 Display Engine
2022-10-31 16:51:01 +08:00
initUiBlender();
2022-10-31 16:40:59 +08:00
2022-10-31 15:43:07 +08:00
// Init the Base UI Channel
2022-10-31 16:51:01 +08:00
initUiChannel(
2022-10-31 15:43:07 +08:00
1, // UI Channel Number (1 for Base UI Channel)
planeInfo.fbmem, // Start of frame buffer memory
planeInfo.fblen, // Length of frame buffer memory in bytes
planeInfo.stride, // Length of a line in bytes (4 bytes per pixel)
planeInfo.xres_virtual, // Horizontal resolution in pixel columns
planeInfo.yres_virtual, // Vertical resolution in pixel rows
planeInfo.xoffset, // Horizontal offset in pixel columns
planeInfo.yoffset, // Vertical offset in pixel rows
);
// Init the 2 Overlay UI Channels
2022-11-01 13:43:18 +08:00
for (overlayInfo) | ov, ov_index | {
2022-10-31 16:51:01 +08:00
initUiChannel(
2022-11-01 13:43:18 +08:00
@intCast(u8, ov_index + 2), // UI Channel Number (2 and 3 for Overlay UI Channels)
2022-10-31 15:43:07 +08:00
ov.fbmem, // Start of frame buffer memory
ov.fblen, // Length of frame buffer memory in bytes
ov.stride, // Length of a line in bytes (4 bytes per pixel)
ov.sarea.w, // Horizontal resolution in pixel columns
ov.sarea.h, // Vertical resolution in pixel rows
ov.sarea.x, // Horizontal offset in pixel columns
ov.sarea.y, // Vertical offset in pixel rows
);
}
2022-10-31 17:18:21 +08:00
// TODO
applySettings();
2022-10-31 16:40:59 +08:00
}
2022-10-31 18:14:19 +08:00
/// Hardware Registers for PinePhone's A64 Display Engine.
/// See https://lupyuen.github.io/articles/de#appendix-overview-of-allwinner-a64-display-engine
2022-10-31 19:04:36 +08:00
/// Display Engine Base Address is 0x0100 0000
2022-10-31 18:02:26 +08:00
const DISPLAY_ENGINE_BASE_ADDRESS = 0x0100_0000;
/// RT-MIXER0 is at DE Offset 0x10 0000 (Page 87)
const MIXER0_BASE_ADDRESS = DISPLAY_ENGINE_BASE_ADDRESS + 0x10_0000;
2022-10-31 19:04:36 +08:00
// |GLB | 0x0000
2022-10-31 18:02:26 +08:00
const GLB_BASE_ADDRESS = MIXER0_BASE_ADDRESS + 0x0000;
2022-10-31 19:04:36 +08:00
// |BLD (Blender) | 0x1000
2022-10-31 18:02:26 +08:00
const BLD_BASE_ADDRESS = MIXER0_BASE_ADDRESS + 0x1000;
2022-10-31 19:04:36 +08:00
// |OVL_UI(CH1) (UI Overlay / Channel 1) | 0x3000
// |OVL_UI(CH2) (UI Overlay / Channel 2) | 0x4000
// |OVL_UI(CH3) (UI Overlay / Channel 3) | 0x5000
2022-10-31 18:14:19 +08:00
const OVL_UI_CH1_BASE_ADDRESS = MIXER0_BASE_ADDRESS + 0x3000;
2022-10-31 18:02:26 +08:00
2022-10-31 17:08:08 +08:00
/// Initialise the UI Blender for PinePhone's A64 Display Engine.
/// See https://lupyuen.github.io/articles/de#appendix-programming-the-allwinner-a64-display-engine
2022-10-31 16:51:01 +08:00
fn initUiBlender() void {
2022-11-01 11:38:02 +08:00
debug("initUiBlender\nConfigure Blender", .{});
2022-10-31 18:04:44 +08:00
2022-10-31 16:40:59 +08:00
// BLD_BK_COLOR @ BLD Offset 0x88: BLD background color register
2022-10-31 18:18:17 +08:00
// Set to 0xff00 0000 (Why?)
2022-10-31 18:02:26 +08:00
const BLD_BK_COLOR = BLD_BASE_ADDRESS + 0x88;
putreg32(0xff00_0000, BLD_BK_COLOR);
2022-10-31 15:43:07 +08:00
2022-10-31 16:40:59 +08:00
// BLD_PREMUL_CTL @ BLD Offset 0x84: BLD pre-multiply control register
2022-10-31 18:02:26 +08:00
// Set to 0
const BLD_PREMUL_CTL = BLD_BASE_ADDRESS + 0x84;
putreg32(0, BLD_PREMUL_CTL);
2022-10-31 11:56:43 +08:00
}
2022-10-31 12:18:57 +08:00
2022-10-31 17:18:21 +08:00
/// TODO
fn applySettings() void {
2022-11-01 11:38:02 +08:00
debug("applySettings\nSet BLD Route and BLD FColor Control", .{});
2022-10-31 19:04:36 +08:00
// Set BLD Route and BLD FColor Control
// - BLD Route (BLD_CH_RTCTL @ BLD Offset 0x080): _BLD routing control register_
// Set to 0x321 (Why?)
const BLD_CH_RTCTL = BLD_BASE_ADDRESS + 0x080;
putreg32(0x321, BLD_CH_RTCTL);
// - BLD FColor Control (BLD_FILLCOLOR_CTL @ BLD Offset 0x000): _BLD fill color control register_
// Set to 0x701 (Why?)
const BLD_FILLCOLOR_CTL = BLD_BASE_ADDRESS + 0x000;
putreg32(0x701, BLD_FILLCOLOR_CTL);
// Apply Settings
// - GLB DBuff (GLB_DBUFFER @ GLB Offset 0x008): _Global double buffer control register_
// Set to 1 (Why?)
2022-11-01 11:36:40 +08:00
debug("Apply Settings", .{});
2022-10-31 19:04:36 +08:00
const GLB_DBUFFER = GLB_BASE_ADDRESS + 0x008;
putreg32(1, GLB_DBUFFER);
2022-10-31 17:18:21 +08:00
}
2022-10-31 15:43:07 +08:00
/// Initialise a UI Channel for PinePhone's A64 Display Engine.
2022-10-31 17:08:08 +08:00
/// We use 3 UI Channels: Base UI Channel (#1) plus 2 Overlay UI Channels (#2, #3).
/// See https://lupyuen.github.io/articles/de#appendix-programming-the-allwinner-a64-display-engine
2022-10-31 15:43:07 +08:00
fn initUiChannel(
channel: u8, // UI Channel Number: 1, 2 or 3
2022-10-31 17:08:08 +08:00
fbmem: ?*anyopaque, // Start of frame buffer memory, or null if this channel should be disabled
2022-10-31 15:43:07 +08:00
fblen: usize, // Length of frame buffer memory in bytes
stride: c.fb_coord_t, // Length of a line in bytes (4 bytes per pixel)
xres: c.fb_coord_t, // Horizontal resolution in pixel columns
yres: c.fb_coord_t, // Vertical resolution in pixel rows
xoffset: c.fb_coord_t, // Horizontal offset in pixel columns
yoffset: c.fb_coord_t, // Vertical offset in pixel rows
2022-10-31 16:51:01 +08:00
) void {
2022-10-31 18:02:26 +08:00
debug("initUiChannel", .{});
2022-10-31 15:43:07 +08:00
assert(channel >= 1 and channel <= 3);
2022-10-31 17:48:39 +08:00
assert(fblen == @intCast(usize, xres) * yres * 4);
assert(stride == @intCast(usize, xres) * 4);
2022-10-31 15:43:07 +08:00
2022-10-31 19:33:11 +08:00
// |OVL_UI(CH1) (UI Overlay / Channel 1) | 0x3000
// |OVL_UI(CH2) (UI Overlay / Channel 2) | 0x4000
// |OVL_UI(CH3) (UI Overlay / Channel 3) | 0x5000
2022-11-01 11:13:59 +08:00
const OVL_UI_BASE_ADDRESS = OVL_UI_CH1_BASE_ADDRESS +
2022-10-31 19:33:11 +08:00
@intCast(u64, channel - 1) * 0x1000;
2022-10-31 17:08:08 +08:00
// If UI Channel should be disabled...
if (fbmem == null) {
2022-11-01 11:36:40 +08:00
// Disable Overlay and Pipe:
2022-10-31 19:04:36 +08:00
// UI Config Attr (OVL_UI_ATTCTL @ OVL_UI Offset 0x00): _OVL_UI attribute control register_
2022-10-31 19:33:11 +08:00
// Set to 0
2022-11-01 11:36:40 +08:00
debug("Channel {}: Disable Overlay and Pipe", .{ channel });
2022-11-01 11:13:59 +08:00
const OVL_UI_ATTCTL = OVL_UI_BASE_ADDRESS + 0x00;
2022-10-31 19:33:11 +08:00
putreg32(0, OVL_UI_ATTCTL);
2022-10-31 17:08:08 +08:00
2022-11-01 11:36:40 +08:00
// Disable Scaler:
2022-10-31 19:04:36 +08:00
// Mixer (??? @ 0x113 0000 + 0x10000 * Channel)
2022-10-31 19:33:11 +08:00
// Set to 0
2022-11-01 11:36:40 +08:00
debug("Channel {}: Disable Scaler", .{ channel });
2022-10-31 19:33:11 +08:00
const MIXER = 0x113_0000 + 0x10000 * @intCast(u64, channel);
putreg32(0, MIXER);
2022-10-31 17:08:08 +08:00
2022-10-31 19:33:11 +08:00
// Skip to next UI Channel
return;
2022-10-31 17:08:08 +08:00
}
2022-10-31 19:04:36 +08:00
// 1. Set Overlay (Assume Layer = 0)
// - UI Config Attr (OVL_UI_ATTCTL @ OVL_UI Offset 0x00): _OVL_UI attribute control register_
// For Channel 1: Set to 0xff00 0405 (Why?)
// For Channel 2: 0xff00 0005 (Why?)
// For Channel 3: 0x7f00 0005 (Why?)
2022-11-01 11:36:40 +08:00
debug("Channel {}: Set Overlay ({} x {})", .{ channel, xres, yres });
2022-11-01 11:13:59 +08:00
const OVL_UI_ATTCTL = OVL_UI_BASE_ADDRESS + 0x00;
2022-10-31 18:14:19 +08:00
if (channel == 1) { putreg32(0xff00_0405, OVL_UI_ATTCTL); }
2022-10-31 18:18:17 +08:00
else if (channel == 2) { putreg32(0xff00_0005, OVL_UI_ATTCTL); }
else if (channel == 3) { putreg32(0x7f00_0005, OVL_UI_ATTCTL); }
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// - UI Config Top LAddr (OVL_UI_TOP_LADD @ OVL_UI Offset 0x10): _OVL_UI top field memory block low address register_
// Set to Framebuffer Address: fb0, fb1 or fb2
2022-11-01 11:13:59 +08:00
const OVL_UI_TOP_LADD = OVL_UI_BASE_ADDRESS + 0x10;
2022-10-31 19:33:11 +08:00
putreg32(@intCast(u32, @ptrToInt(fbmem.?)), OVL_UI_TOP_LADD);
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// - UI Config Pitch (OVL_UI_PITCH @ OVL_UI Offset 0x0C): _OVL_UI memory pitch register_
// Set to (width * 4)
2022-11-01 11:13:59 +08:00
const OVL_UI_PITCH = OVL_UI_BASE_ADDRESS + 0x0C;
2022-10-31 19:33:11 +08:00
putreg32(xres * 4, OVL_UI_PITCH);
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// - UI Config Size (OVL_UI_MBSIZE @ OVL_UI Offset 0x04): _OVL_UI memory block size register_
// Set to (height-1) << 16 + (width-1)
2022-11-01 11:13:59 +08:00
const OVL_UI_MBSIZE = OVL_UI_BASE_ADDRESS + 0x04;
const height_width: u32 = @intCast(u32, yres - 1) << 16
| (xres - 1);
putreg32(height_width, OVL_UI_MBSIZE);
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// - UI Overlay Size (OVL_UI_SIZE @ OVL_UI Offset 0x88): _OVL_UI overlay window size register_
// Set to (height-1) << 16 + (width-1)
2022-11-01 11:13:59 +08:00
const OVL_UI_SIZE = OVL_UI_BASE_ADDRESS + 0x88;
putreg32(height_width, OVL_UI_SIZE);
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// - IO Config Coord (OVL_UI_COOR @ OVL_UI Offset 0x08): _OVL_UI memory block coordinate register_
2022-10-31 17:18:21 +08:00
// Set to 0
2022-11-01 11:13:59 +08:00
const OVL_UI_COOR = OVL_UI_BASE_ADDRESS + 0x08;
2022-10-31 19:33:11 +08:00
putreg32(0, OVL_UI_COOR);
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// 1. For Channel 1: Set Blender Output
2022-11-01 11:36:40 +08:00
if (channel == 1) {
2022-10-31 19:33:11 +08:00
// - BLD Output Size (BLD_SIZE @ BLD Offset 0x08C): _BLD output size setting register_
// Set to (height-1) << 16 + (width-1)
2022-11-01 11:36:40 +08:00
debug("Channel {}: Set Blender Output", .{ channel });
2022-10-31 19:33:11 +08:00
const BLD_SIZE = BLD_BASE_ADDRESS + 0x08C;
2022-11-01 11:13:59 +08:00
putreg32(height_width, BLD_SIZE);
2022-10-31 19:33:11 +08:00
// - GLB Size (GLB_SIZE @ GLB Offset 0x00C): _Global size register_
// Set to (height-1) << 16 + (width-1)
const GLB_SIZE = GLB_BASE_ADDRESS + 0x00C;
2022-11-01 11:13:59 +08:00
putreg32(height_width, GLB_SIZE);
2022-10-31 19:33:11 +08:00
}
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// 1. Set Blender Input Pipe (N = Pipe Number, from 0 to 2 for Channels 1 to 3)
2022-10-31 19:33:11 +08:00
const pipe: u64 = channel - 1;
2022-11-01 11:36:40 +08:00
debug("Channel {}: Set Blender Input Pipe {} ({} x {})", .{ channel, pipe, xres, yres });
2022-10-31 19:33:11 +08:00
2022-10-31 19:04:36 +08:00
// - BLD Pipe InSize (BLD_CH_ISIZE @ BLD Offset 0x008 + N*0x10): _BLD input memory size register(N=0,1,2,3,4)_
// Set to (height-1) << 16 + (width-1)
2022-10-31 19:33:11 +08:00
const BLD_CH_ISIZE = BLD_BASE_ADDRESS + 0x008 + pipe * 0x10;
2022-11-01 11:13:59 +08:00
putreg32(height_width, BLD_CH_ISIZE);
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// - BLD Pipe FColor (BLD_FILL_COLOR @ BLD Offset 0x004 + N*0x10): _BLD fill color register(N=0,1,2,3,4)_
// Set to 0xff00 0000 (Why?)
2022-10-31 19:33:11 +08:00
const BLD_FILL_COLOR = BLD_BASE_ADDRESS + 0x004 + pipe * 0x10;
putreg32(0xff00_0000, BLD_FILL_COLOR);
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// - BLD Pipe Offset (BLD_CH_OFFSET @ BLD Offset 0x00C + N*0x10): _BLD input memory offset register(N=0,1,2,3,4)_
2022-10-31 19:33:11 +08:00
// For Channel 1: Set to 0 (Why?)
// For Channel 2: Set to 0x34 0034 (Why?)
// For Channel 3: Set to 0 (Why?)
_ = xoffset; ////
_ = yoffset; ////
const BLD_CH_OFFSET = BLD_BASE_ADDRESS + 0x00C + pipe * 0x10;
if (channel == 1) { putreg32(0, BLD_CH_OFFSET); }
else if (channel == 2) { putreg32(0x34_0034, BLD_CH_OFFSET); }
else if (channel == 3) { putreg32(0, BLD_CH_OFFSET); }
2022-10-31 17:18:21 +08:00
2022-11-01 11:48:06 +08:00
// - BLD Pipe Mode (BLD_CTL @ BLD Offset 0x090 + N*4): _BLD control register_
2022-10-31 19:04:36 +08:00
// Set to 0x301 0301 (Why?)
2022-11-01 11:52:57 +08:00
const BLD_CTL = BLD_BASE_ADDRESS + 0x090 + pipe * 4;
2022-11-01 11:48:06 +08:00
putreg32(0x301_0301, BLD_CTL);
2022-10-31 17:18:21 +08:00
2022-11-01 11:48:06 +08:00
// Note: Log shows BLD_CH_ISIZE, BLD_FILL_COLOR and BLD_CH_OFFSET are at N*0x10, but doc says N*0x14
2022-10-31 17:18:21 +08:00
2022-10-31 19:04:36 +08:00
// 1. Disable Scaler (Assume we're not scaling)
// - Mixer (??? @ 0x113 0000 + 0x10000 * Channel)
2022-10-31 17:18:21 +08:00
// Set to 0
2022-11-01 11:36:40 +08:00
debug("Channel {}: Disable Scaler", .{ channel });
2022-10-31 19:33:11 +08:00
const MIXER = 0x113_0000 + 0x10000 * @intCast(u64, channel);
putreg32(0, MIXER);
2022-10-31 15:43:07 +08:00
}
2022-10-31 17:48:39 +08:00
/// Set the 32-bit value at the address
fn putreg32(val: u32, addr: u64) void {
debug(" *0x{x} = 0x{x}", .{ addr, val });
const ptr = @intToPtr(*volatile u32, addr);
ptr.* = val;
}
2022-10-31 14:27:57 +08:00
/// Export MIPI DSI Functions to C. (Why is this needed?)
pub export fn export_dsi_functions() void {
// Export Panel Init Function
2022-10-31 12:18:57 +08:00
dsi.nuttx_panel_init();
}
2022-10-31 12:37:58 +08:00
2022-10-31 14:34:21 +08:00
/// NuttX Video Controller for PinePhone (3 UI Channels)
2022-10-31 12:37:58 +08:00
const videoInfo = c.fb_videoinfo_s {
2022-10-31 15:52:57 +08:00
.fmt = c.FB_FMT_RGBA32, // Pixel format (XRGB 8888)
2022-10-31 13:56:10 +08:00
.xres = 720, // Horizontal resolution in pixel columns
.yres = 1440, // Vertical resolution in pixel rows
.nplanes = 1, // Number of color planes supported (Base UI Channel)
.noverlays = 2, // Number of overlays supported (2 Overlay UI Channels)
2022-10-31 12:37:58 +08:00
};
2022-10-31 15:52:57 +08:00
/// NuttX Color Plane for PinePhone (Base UI Channel):
/// Fullscreen 720 x 1440 (4 bytes per XRGB 8888 pixel)
2022-10-31 12:37:58 +08:00
const planeInfo = c.fb_planeinfo_s {
2022-10-31 14:27:57 +08:00
.fbmem = &fb0, // Start of frame buffer memory
.fblen = @sizeOf( @TypeOf(fb0) ), // Length of frame buffer memory in bytes
.stride = 720 * 4, // Length of a line in bytes (4 bytes per pixel)
.display = 0, // Display number (Unused)
2022-10-31 15:52:57 +08:00
.bpp = 32, // Bits per pixel (XRGB 8888)
2022-10-31 14:27:57 +08:00
.xres_virtual = 720, // Virtual Horizontal resolution in pixel columns
.yres_virtual = 1440, // Virtual Vertical resolution in pixel rows
.xoffset = 0, // Offset from virtual to visible resolution
.yoffset = 0, // Offset from virtual to visible resolution
2022-10-31 12:45:56 +08:00
};
2022-10-31 14:34:21 +08:00
/// NuttX Overlays for PinePhone (2 Overlay UI Channels)
2022-10-31 13:56:10 +08:00
const overlayInfo = [2] c.fb_overlayinfo_s {
// First Overlay UI Channel:
2022-10-31 15:52:57 +08:00
// Square 600 x 600 (4 bytes per ARGB 8888 pixel)
2022-10-31 13:56:10 +08:00
.{
2022-10-31 14:04:58 +08:00
.fbmem = &fb1, // Start of frame buffer memory
2022-10-31 14:25:41 +08:00
.fblen = @sizeOf( @TypeOf(fb1) ), // Length of frame buffer memory in bytes
2022-10-31 14:04:58 +08:00
.stride = 600 * 4, // Length of a line in bytes
.overlay = 0, // Overlay number (First Overlay)
2022-10-31 15:52:57 +08:00
.bpp = 32, // Bits per pixel (ARGB 8888)
2022-10-31 14:04:58 +08:00
.blank = 0, // TODO: Blank or unblank
.chromakey = 0, // TODO: Chroma key argb8888 formatted
.color = 0, // TODO: Color argb8888 formatted
.transp = c.fb_transp_s { .transp = 0, .transp_mode = 0 }, // TODO: Transparency
.sarea = c.fb_area_s { .x = 52, .y = 52, .w = 600, .h = 600 }, // Selected area within the overlay
.accl = 0, // TODO: Supported hardware acceleration
2022-10-31 13:56:10 +08:00
},
// Second Overlay UI Channel:
2022-10-31 15:52:57 +08:00
// Fullscreen 720 x 1440 (4 bytes per ARGB 8888 pixel)
2022-10-31 13:56:10 +08:00
.{
2022-10-31 14:04:58 +08:00
.fbmem = &fb2, // Start of frame buffer memory
2022-10-31 14:25:41 +08:00
.fblen = @sizeOf( @TypeOf(fb2) ), // Length of frame buffer memory in bytes
2022-10-31 14:04:58 +08:00
.stride = 720 * 4, // Length of a line in bytes
.overlay = 1, // Overlay number (Second Overlay)
2022-10-31 15:52:57 +08:00
.bpp = 32, // Bits per pixel (ARGB 8888)
2022-10-31 14:04:58 +08:00
.blank = 0, // TODO: Blank or unblank
.chromakey = 0, // TODO: Chroma key argb8888 formatted
.color = 0, // TODO: Color argb8888 formatted
.transp = c.fb_transp_s { .transp = 0, .transp_mode = 0 }, // TODO: Transparency
.sarea = c.fb_area_s { .x = 0, .y = 0, .w = 720, .h = 1440 }, // Selected area within the overlay
.accl = 0, // TODO: Supported hardware acceleration
2022-10-31 13:56:10 +08:00
},
};
2022-10-31 13:48:27 +08:00
// Framebuffer 0: (Base UI Channel)
2022-10-31 15:52:57 +08:00
// Fullscreen 720 x 1440 (4 bytes per XRGB 8888 pixel)
2022-10-31 13:48:27 +08:00
var fb0 = std.mem.zeroes([720 * 1440] u32);
// Framebuffer 1: (First Overlay UI Channel)
2022-10-31 15:52:57 +08:00
// Square 600 x 600 (4 bytes per ARGB 8888 pixel)
2022-10-31 13:48:27 +08:00
var fb1 = std.mem.zeroes([600 * 600] u32);
// Framebuffer 2: (Second Overlay UI Channel)
2022-10-31 15:52:57 +08:00
// Fullscreen 720 x 1440 (4 bytes per ARGB 8888 pixel)
2022-10-31 13:48:27 +08:00
var fb2 = std.mem.zeroes([720 * 1440] u32);
2022-10-31 14:25:41 +08:00
///////////////////////////////////////////////////////////////////////////////
// Panic Handler
/// Called by Zig when it hits a Panic. We print the Panic Message, Stack Trace and halt. See
/// https://andrewkelley.me/post/zig-stack-traces-kernel-panic-bare-bones-os.html
/// https://github.com/ziglang/zig/blob/master/lib/std/builtin.zig#L763-L847
pub fn panic(
message: []const u8,
_stack_trace: ?*std.builtin.StackTrace
) noreturn {
// Print the Panic Message
_ = _stack_trace;
_ = puts("\n!ZIG PANIC!");
_ = puts(@ptrCast([*c]const u8, message));
// Print the Stack Trace
_ = puts("Stack Trace:");
var it = std.debug.StackIterator.init(@returnAddress(), null);
while (it.next()) |return_address| {
_ = printf("%p\n", return_address);
}
// Halt
c.exit(1);
}
///////////////////////////////////////////////////////////////////////////////
// Logging
/// Called by Zig for `std.log.debug`, `std.log.info`, `std.log.err`, ...
/// https://gist.github.com/leecannon/d6f5d7e5af5881c466161270347ce84d
pub fn log(
comptime _message_level: std.log.Level,
comptime _scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: anytype,
) void {
_ = _message_level;
_ = _scope;
// Format the message
var buf: [100]u8 = undefined; // Limit to 100 chars
var slice = std.fmt.bufPrint(&buf, format, args)
catch { _ = puts("*** log error: buf too small"); return; };
// Terminate the formatted message with a null
var buf2: [buf.len + 1 : 0]u8 = undefined;
std.mem.copy(
u8,
buf2[0..slice.len],
slice[0..slice.len]
);
buf2[slice.len] = 0;
// Print the formatted message
_ = puts(&buf2);
}
///////////////////////////////////////////////////////////////////////////////
// Imported Functions and Variables
/// For safety, we import these functions ourselves to enforce Null-Terminated Strings.
/// We changed `[*c]const u8` to `[*:0]const u8`
extern fn printf(format: [*:0]const u8, ...) c_int;
extern fn puts(str: [*:0]const u8) c_int;
/// Aliases for Zig Standard Library
const assert = std.debug.assert;
const debug = std.log.debug;