From f9bd04ff19c9e7d9c67687bfe5f04dda7d61f4cb Mon Sep 17 00:00:00 2001 From: Lee Lup Yuen Date: Tue, 27 Dec 2022 12:21:37 +0800 Subject: [PATCH] arm64/pinephone: Add driver for Frame Buffer This PR adds the Frame Buffer Driver for PINE64 PinePhone. With this driver, NuttX Apps will be able to use the standard Frame Buffer API to render graphics on PinePhone. `boards/arm64/a64/pinephone/src/pinephone_bringup.c`: Render Test Pattern after calling `up_fbinitialize()` to start the Frame Buffer Driver `boards/arm64/a64/pinephone/src/pinephone_display.c`: Add Frame Buffer Driver `boards/arm64/a64/pinephone/src/pinephone_display.h`: Declare new function for rendering Test Pattern `platforms/arm/a64/boards/pinephone/index.rst`: Add Frame Buffer as supported driver for PinePhone --- .../arm/a64/boards/pinephone/index.rst | 1 + .../a64/pinephone/src/pinephone_bringup.c | 5 + .../a64/pinephone/src/pinephone_display.c | 560 ++++++++++++++---- .../a64/pinephone/src/pinephone_display.h | 52 ++ 4 files changed, 487 insertions(+), 131 deletions(-) create mode 100644 boards/arm64/a64/pinephone/src/pinephone_display.h diff --git a/Documentation/platforms/arm/a64/boards/pinephone/index.rst b/Documentation/platforms/arm/a64/boards/pinephone/index.rst index c7e79a61e2..951390adf6 100644 --- a/Documentation/platforms/arm/a64/boards/pinephone/index.rst +++ b/Documentation/platforms/arm/a64/boards/pinephone/index.rst @@ -157,6 +157,7 @@ Peripheral Support NOTES ======================= ======= ===== Backlight Yes Display Engine Yes +Frame Buffer Yes LCD Controller (ST7703) Yes LCD Panel (XBD599) Yes MIPI D-PHY Yes diff --git a/boards/arm64/a64/pinephone/src/pinephone_bringup.c b/boards/arm64/a64/pinephone/src/pinephone_bringup.c index 1ba75f1fbf..56029a2176 100644 --- a/boards/arm64/a64/pinephone/src/pinephone_bringup.c +++ b/boards/arm64/a64/pinephone/src/pinephone_bringup.c @@ -36,6 +36,7 @@ #ifdef CONFIG_VIDEO_FB # include +# include "pinephone_display.h" #endif #include "pinephone.h" @@ -84,6 +85,10 @@ int pinephone_bringup(void) { syslog(LOG_ERR, "ERROR: fb_register() failed: %d\n", ret); } + + /* Render the Test Pattern */ + + pinephone_display_test_pattern(); #endif UNUSED(ret); diff --git a/boards/arm64/a64/pinephone/src/pinephone_display.c b/boards/arm64/a64/pinephone/src/pinephone_display.c index 3d8541bc11..d5da23f0df 100644 --- a/boards/arm64/a64/pinephone/src/pinephone_display.c +++ b/boards/arm64/a64/pinephone/src/pinephone_display.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ #include "a64_tcon0.h" #include "pinephone_lcd.h" #include "pinephone_pmic.h" +#include "pinephone_display.h" /**************************************************************************** * Pre-processor Definitions @@ -76,10 +78,53 @@ #define FB1_WIDTH 600 #define FB1_HEIGHT 600 +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int pinephone_getvideoinfo(struct fb_vtable_s *vtable, + struct fb_videoinfo_s *vinfo); + +static int pinephone_getplaneinfo(struct fb_vtable_s *vtable, int planeno, + struct fb_planeinfo_s *pinfo); + +static int pinephone_getoverlayinfo(struct fb_vtable_s *vtable, + int overlayno, + struct fb_overlayinfo_s *oinfo); + +static int pinephone_settransp(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo); + +static int pinephone_setchromakey(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo); + +static int pinephone_setcolor(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo); + +static int pinephone_setblank(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo); + +static int pinephone_setarea(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo); + /**************************************************************************** * Private Data ****************************************************************************/ +/* Vtable for Frame Buffer Operations */ + +static struct fb_vtable_s g_pinephone_vtable = +{ + .getvideoinfo = pinephone_getvideoinfo, + .getplaneinfo = pinephone_getplaneinfo, + .getoverlayinfo = pinephone_getoverlayinfo, + .settransp = pinephone_settransp, + .setchromakey = pinephone_setchromakey, + .setcolor = pinephone_setcolor, + .setblank = pinephone_setblank, + .setarea = pinephone_setarea +}; + /* Frame Buffers for Display Engine *****************************************/ /* Frame Buffer 0: (Base UI Channel) @@ -195,130 +240,6 @@ static struct fb_overlayinfo_s g_pinephone_overlays[2] = * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: test_pattern - * - * Description: - * Fill the 3 Frame Buffers with a Test Pattern. Should be called after - * Display Engine is Enabled, or the rendered image will have missing - * rows. - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void test_pattern(void) -{ - int i; - int x; - int y; - const int fb0_len = sizeof(g_pinephone_fb0) / sizeof(g_pinephone_fb0[0]); - const int fb1_len = sizeof(g_pinephone_fb1) / sizeof(g_pinephone_fb1[0]); - - /* Zero the Framebuffers */ - - memset(g_pinephone_fb0, 0, sizeof(g_pinephone_fb0)); - memset(g_pinephone_fb1, 0, sizeof(g_pinephone_fb1)); - memset(g_pinephone_fb2, 0, sizeof(g_pinephone_fb2)); - - /* Init Framebuffer 0: - * Fill with Blue, Green and Red - */ - - for (i = 0; i < fb0_len; i++) - { - /* Colours are in XRGB 8888 format */ - - if (i < fb0_len / 4) - { - /* Blue for top quarter */ - - g_pinephone_fb0[i] = 0x80000080; - } - else if (i < fb0_len / 2) - { - /* Green for next quarter */ - - g_pinephone_fb0[i] = 0x80008000; - } - else - { - /* Red for lower half */ - - g_pinephone_fb0[i] = 0x80800000; - } - - /* Fixes missing rows in the rendered image, not sure why */ - - ARM64_DMB(); - ARM64_DSB(); - ARM64_ISB(); - } - - /* Init Framebuffer 1: - * Fill with Semi-Transparent White - */ - - for (i = 0; i < fb1_len; i++) - { - /* Semi-Transparent White in ARGB 8888 format */ - - g_pinephone_fb1[i] = 0x40ffffff; - - /* Fixes missing rows in the rendered image, not sure why */ - - ARM64_DMB(); - ARM64_DSB(); - ARM64_ISB(); - } - - /* Init Framebuffer 2: - * Fill with Semi-Transparent Green Circle - */ - - for (y = 0; y < PANEL_HEIGHT; y++) - { - for (x = 0; x < PANEL_WIDTH; x++) - { - /* Get pixel index */ - - const int p = (y * PANEL_WIDTH) + x; - - /* Shift coordinates so that centre of screen is (0,0) */ - - const int half_width = PANEL_WIDTH / 2; - const int half_height = PANEL_HEIGHT / 2; - const int x_shift = x - half_width; - const int y_shift = y - half_height; - - /* If x^2 + y^2 < radius^2, set to Semi-Transparent Green */ - - if (x_shift*x_shift + y_shift*y_shift < half_width*half_width) - { - /* Semi-Transparent Green in ARGB 8888 Format */ - - g_pinephone_fb2[p] = 0x80008000; - } - else /* Otherwise set to Transparent Black */ - { - /* Transparent Black in ARGB 8888 Format */ - - g_pinephone_fb2[p] = 0x00000000; - } - - /* Fixes missing rows in the rendered image, not sure why */ - - ARM64_DMB(); - ARM64_DSB(); - ARM64_ISB(); - } - } -} - /**************************************************************************** * Name: render_framebuffers * @@ -418,16 +339,266 @@ static int render_framebuffers(void) return ret; } - /* Fill Frame Buffers with Test Pattern. Should be called after - * Display Engine is Enabled, or the rendered image will have - * missing rows. + return OK; +} + +/**************************************************************************** + * Name: pinephone_getvideoinfo + * + * Description: + * Get the videoinfo for the framebuffer. (ioctl Entrypoint: + * FBIOGET_VIDEOINFO) + * + * Input Parameters: + * vtable - Framebuffer driver object + * vinfo - Returned videoinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int pinephone_getvideoinfo(struct fb_vtable_s *vtable, + struct fb_videoinfo_s *vinfo) +{ + static int stage = 0; + + ginfo("vtable=%p vinfo=%p\n", vtable, vinfo); + DEBUGASSERT(vtable != NULL && vtable == &g_pinephone_vtable && + vinfo != NULL); + + /* Copy and return the videoinfo object */ + + memcpy(vinfo, &g_pinephone_video, sizeof(struct fb_videoinfo_s)); + + /* Keep track of the stages during startup: + * Stage 0: Initialize driver at startup + * Stage 1: First call by apps + * Stage 2: Subsequent calls by apps + * We erase the framebuffers at stages 0 and 1. This allows the + * Test Pattern to be displayed for as long as possible before erasure. */ - test_pattern(); + if (stage < 2) + { + stage++; + memset(g_pinephone_fb0, 0, sizeof(g_pinephone_fb0)); + memset(g_pinephone_fb1, 0, sizeof(g_pinephone_fb1)); + memset(g_pinephone_fb2, 0, sizeof(g_pinephone_fb2)); + } return OK; } +/**************************************************************************** + * Name: pinephone_getplaneinfo + * + * Description: + * Get the planeinfo for the framebuffer. (ioctl Entrypoint: + * FBIOGET_PLANEINFO) + * + * Input Parameters: + * vtable - Framebuffer driver object + * pinfo - Returned planeinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int pinephone_getplaneinfo(struct fb_vtable_s *vtable, int planeno, + struct fb_planeinfo_s *pinfo) +{ + DEBUGASSERT(vtable != NULL && vtable == &g_pinephone_vtable); + ginfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo); + + /* Copy and return the planeinfo object */ + + if (planeno == 0) + { + memcpy(pinfo, &g_pinephone_plane, sizeof(struct fb_planeinfo_s)); + return OK; + } + + gerr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: pinephone_getoverlayinfo + * + * Description: + * Get the overlayinfo for the framebuffer. (ioctl Entrypoint: + * FBIOGET_OVERLAYINFO) + * + * Input Parameters: + * vtable - Framebuffer driver object + * overlayno - Overlay number + * oinfo - Returned overlayinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int pinephone_getoverlayinfo(struct fb_vtable_s *vtable, + int overlayno, + struct fb_overlayinfo_s *oinfo) +{ + const int overlay_len = sizeof(g_pinephone_overlays) / + sizeof(g_pinephone_overlays[0]); + + ginfo("vtable=%p overlay=%d oinfo=%p\n", vtable, overlayno, oinfo); + DEBUGASSERT(vtable != NULL && vtable == &g_pinephone_vtable); + + /* Copy and return the overlayinfo object */ + + if (overlayno >= 0 && overlayno < overlay_len) + { + struct fb_overlayinfo_s *overlay = &g_pinephone_overlays[overlayno]; + + memcpy(oinfo, overlay, sizeof(struct fb_overlayinfo_s)); + return OK; + } + + gerr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: pinephone_settransp + * + * Description: + * Set the overlay transparency for the framebuffer. (ioctl Entrypoint: + * FBIOSET_TRANSP) + * + * Input Parameters: + * vtable - Framebuffer driver object + * oinfo - overlayinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int pinephone_settransp(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo) +{ + DEBUGASSERT(vtable != NULL && vtable == &g_pinephone_vtable); + ginfo("vtable=%p, overlay=%d, transp=%02x, transp_mode=%02x\n", vtable, + oinfo->overlay, oinfo->transp.transp, oinfo->transp.transp_mode); + gerr("Not implemented"); + return OK; +} + +/**************************************************************************** + * Name: pinephone_setchromakey + * + * Description: + * Set the overlay chroma key for the framebuffer. (ioctl Entrypoint: + * FBIOSET_CHROMAKEY) + * + * Input Parameters: + * vtable - Framebuffer driver object + * oinfo - overlayinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int pinephone_setchromakey(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo) +{ + DEBUGASSERT(vtable != NULL && vtable == &g_pinephone_vtable && + oinfo != NULL); + ginfo("vtable=%p, overlay=%d, chromakey=%08x\n", vtable, + oinfo->overlay, oinfo->chromakey); + gerr("Not implemented"); + return OK; +} + +/**************************************************************************** + * Name: pinephone_setcolor + * + * Description: + * Set the overlay color for the framebuffer. (ioctl Entrypoint: + * FBIOSET_COLOR) + * + * Input Parameters: + * vtable - Framebuffer driver object + * oinfo - overlayinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int pinephone_setcolor(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo) +{ + DEBUGASSERT(vtable != NULL && vtable == &g_pinephone_vtable && + oinfo != NULL); + ginfo("vtable=%p, overlay=%d, color=%08x\n", + vtable, oinfo->overlay, oinfo->color); + gerr("Not implemented"); + return OK; +} + +/**************************************************************************** + * Name: pinephone_setblank + * + * Description: + * Set the framebuffer overlay to blank. (ioctl Entrypoint: FBIOSET_BLANK) + * + * Input Parameters: + * vtable - Framebuffer driver object + * oinfo - overlayinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int pinephone_setblank(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo) +{ + DEBUGASSERT(vtable != NULL && vtable == &g_pinephone_vtable && + oinfo != NULL); + ginfo("vtable=%p, overlay=%d, blank=%02x\n", + vtable, oinfo->overlay, oinfo->blank); + gerr("Not implemented"); + return OK; +} + +/**************************************************************************** + * Name: pinephone_setarea + * + * Description: + * Set the overlay area for the framebuffer. (ioctl Entrypoint: + * FBIOSET_AREA) + * + * Input Parameters: + * vtable - Framebuffer driver object + * oinfo - overlayinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int pinephone_setarea(struct fb_vtable_s *vtable, + const struct fb_overlayinfo_s *oinfo) +{ + DEBUGASSERT(vtable != NULL && vtable == &g_pinephone_vtable && + oinfo != NULL); + ginfo("vtable=%p, overlay=%d, x=%d, y=%d, w=%d, h=%d\n", vtable, + oinfo->overlay, oinfo->sarea.x, oinfo->sarea.y, oinfo->sarea.w, + oinfo->sarea.h); + gerr("Not implemented"); + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -585,7 +756,7 @@ int up_fbinitialize(int display) * Name: up_fbgetvplane * * Description: - * Return a a reference to the framebuffer object for the specified video + * Return a reference to the framebuffer object for the specified video * plane of the specified plane. Many OSDs support multiple planes of * video. * @@ -602,10 +773,13 @@ int up_fbinitialize(int display) struct fb_vtable_s *up_fbgetvplane(int display, int vplane) { - /* TODO: Implement up_fbgetvplane */ + ginfo("vplane: %d\n", vplane); DEBUGASSERT(display == 0); - _err("up_fbgetvplane not implemented\n"); + if (vplane == 0) + { + return &g_pinephone_vtable; + } return NULL; } @@ -631,3 +805,127 @@ void up_fbuninitialize(int display) UNUSED(display); } + +/**************************************************************************** + * Name: pinephone_display_test_pattern + * + * Description: + * Fill the 3 Frame Buffers with a Test Pattern. Should be called after + * Display Engine is Enabled, or the rendered image will have missing + * rows. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void pinephone_display_test_pattern(void) +{ + int i; + int x; + int y; + const int fb0_len = sizeof(g_pinephone_fb0) / sizeof(g_pinephone_fb0[0]); + const int fb1_len = sizeof(g_pinephone_fb1) / sizeof(g_pinephone_fb1[0]); + + /* Zero the Framebuffers */ + + memset(g_pinephone_fb0, 0, sizeof(g_pinephone_fb0)); + memset(g_pinephone_fb1, 0, sizeof(g_pinephone_fb1)); + memset(g_pinephone_fb2, 0, sizeof(g_pinephone_fb2)); + + /* Init Framebuffer 0: + * Fill with Blue, Green and Red + */ + + for (i = 0; i < fb0_len; i++) + { + /* Colours are in XRGB 8888 format */ + + if (i < fb0_len / 4) + { + /* Blue for top quarter */ + + g_pinephone_fb0[i] = 0x80000080; + } + else if (i < fb0_len / 2) + { + /* Green for next quarter */ + + g_pinephone_fb0[i] = 0x80008000; + } + else + { + /* Red for lower half */ + + g_pinephone_fb0[i] = 0x80800000; + } + + /* Fixes missing rows in the rendered image, not sure why */ + + ARM64_DMB(); + ARM64_DSB(); + ARM64_ISB(); + } + + /* Init Framebuffer 1: + * Fill with Semi-Transparent White + */ + + for (i = 0; i < fb1_len; i++) + { + /* Semi-Transparent White in ARGB 8888 format */ + + g_pinephone_fb1[i] = 0x40ffffff; + + /* Fixes missing rows in the rendered image, not sure why */ + + ARM64_DMB(); + ARM64_DSB(); + ARM64_ISB(); + } + + /* Init Framebuffer 2: + * Fill with Semi-Transparent Green Circle + */ + + for (y = 0; y < PANEL_HEIGHT; y++) + { + for (x = 0; x < PANEL_WIDTH; x++) + { + /* Get pixel index */ + + const int p = (y * PANEL_WIDTH) + x; + + /* Shift coordinates so that centre of screen is (0,0) */ + + const int half_width = PANEL_WIDTH / 2; + const int half_height = PANEL_HEIGHT / 2; + const int x_shift = x - half_width; + const int y_shift = y - half_height; + + /* If x^2 + y^2 < radius^2, set to Semi-Transparent Green */ + + if (x_shift*x_shift + y_shift*y_shift < half_width*half_width) + { + /* Semi-Transparent Green in ARGB 8888 Format */ + + g_pinephone_fb2[p] = 0x80008000; + } + else /* Otherwise set to Transparent Black */ + { + /* Transparent Black in ARGB 8888 Format */ + + g_pinephone_fb2[p] = 0x00000000; + } + + /* Fixes missing rows in the rendered image, not sure why */ + + ARM64_DMB(); + ARM64_DSB(); + ARM64_ISB(); + } + } +} diff --git a/boards/arm64/a64/pinephone/src/pinephone_display.h b/boards/arm64/a64/pinephone/src/pinephone_display.h new file mode 100644 index 0000000000..714009042e --- /dev/null +++ b/boards/arm64/a64/pinephone/src/pinephone_display.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * boards/arm64/a64/pinephone/src/pinephone_display.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM64_A64_PINEPHONE_SRC_PINEPHONE_DISPLAY_H +#define __BOARDS_ARM64_A64_PINEPHONE_SRC_PINEPHONE_DISPLAY_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: pinephone_display_test_pattern + * + * Description: + * Fill the 3 Frame Buffers with a Test Pattern. Should be called after + * Display Engine is Enabled, or the rendered image will have missing + * rows. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void pinephone_display_test_pattern(void); + +#endif /* __BOARDS_ARM64_A64_PINEPHONE_SRC_PINEPHONE_DISPLAY_H */