1 /*
2  * Copyright (c) 2015 Carlos Pizano-Uribe <cpu@chromium.org>
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 /*
9  * COPYRIGHT(c) 2015 STMicroelectronics
10  *
11  * Redistribution and use in source and binary forms, with or without modification,
12  * are permitted provided that the following conditions are met:
13  *   1. Redistributions of source code must retain the above copyright notice,
14  *      this list of conditions and the following disclaimer.
15  *   2. Redistributions in binary form must reproduce the above copyright notice,
16  *      this list of conditions and the following disclaimer in the documentation
17  *      and/or other materials provided with the distribution.
18  *   3. Neither the name of STMicroelectronics nor the names of its contributors
19  *      may be used to endorse or promote products derived from this software
20  *      without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  ******************************************************************************
34  */
35 
36 #include <assert.h>
37 #include <lk/err.h>
38 #include <lk/debug.h>
39 #include <lk/trace.h>
40 #include <target.h>
41 #include <lk/compiler.h>
42 #include <string.h>
43 #include <dev/gpio.h>
44 #include <dev/display.h>
45 #include <kernel/novm.h>
46 #include <platform/stm32.h>
47 
48 /*
49  * lcd initialization sequence, taken from
50  * STM32Cube_FW_F7_V1.1.0/Drivers/BSP/STM32746G_Disco/stm32746g_discovery_lcd.[ch]
51  *
52  * This code only applies to The RK043FN48H LCD 480x272.
53  */
54 
55 /**
56   * @brief  RK043FN48H Size
57   */
58 #define  RK043FN48H_WIDTH    ((uint16_t)480)    /* LCD PIXEL WIDTH            */
59 #define  RK043FN48H_HEIGHT   ((uint16_t)272)    /* LCD PIXEL HEIGHT           */
60 
61 /**
62   * @brief  RK043FN48H Timing
63   */
64 #define  RK043FN48H_HSYNC      ((uint16_t)41)   /* Horizontal synchronization */
65 #define  RK043FN48H_HBP        ((uint16_t)13)   /* Horizontal back porch      */
66 #define  RK043FN48H_HFP        ((uint16_t)32)   /* Horizontal front porch     */
67 #define  RK043FN48H_VSYNC      ((uint16_t)10)   /* Vertical synchronization   */
68 #define  RK043FN48H_VBP        ((uint16_t)2)    /* Vertical back porch        */
69 #define  RK043FN48H_VFP        ((uint16_t)2)    /* Vertical front porch       */
70 
71 
72 /**
73   * @brief LCD special pins
74   */
75 /* Display enable pin */
76 #define LCD_DISP_PIN            GPIO_PIN_12
77 #define LCD_DISP_GPIO_PORT      GPIOI
78 /* Backlight control pin */
79 #define LCD_BL_CTRL_PIN         GPIO_PIN_3
80 #define LCD_BL_CTRL_GPIO_PORT   GPIOK
81 
82 #define LCD_DISP_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOI_CLK_ENABLE()
83 #define LCD_DISP_GPIO_CLK_DISABLE()     __HAL_RCC_GPIOI_CLK_DISABLE()
84 #define LCD_BL_CTRL_GPIO_CLK_ENABLE()    __HAL_RCC_GPIOK_CLK_ENABLE()
85 #define LCD_BL_CTRL_GPIO_CLK_DISABLE()   __HAL_RCC_GPIOK_CLK_DISABLE()
86 
87 /**
88   * @brief  RK043FN48H frequency divider
89   */
90 #define  RK043FN48H_FREQUENCY_DIVIDER    5      /* LCD Frequency divider      */
91 
92 /** @defgroup STM32746G_DISCOVERY_LCD_Exported_Constants
93   * @{
94   */
95 #define MAX_LAYER_NUMBER       ((uint32_t)2)
96 
97 #define LCD_LayerCfgTypeDef    LTDC_LayerCfgTypeDef
98 
99 #define LTDC_ACTIVE_LAYER        ((uint32_t)1)   /* Layer 1 */
100 /**
101   * @brief  LCD status structure definition
102   */
103 #define LCD_OK                 ((uint8_t)0x00)
104 #define LCD_ERROR              ((uint8_t)0x01)
105 #define LCD_TIMEOUT            ((uint8_t)0x02)
106 
107 
108 static LTDC_HandleTypeDef  ltdc_handle;
109 
110 /* Default LCD configuration with LCD Layer 1 */
111 static uint32_t active_layer = 0;
112 
113 /**
114   * @brief  Gets the LCD X size.
115   * @retval Used LCD X size
116   */
BSP_LCD_GetXSize(void)117 static uint32_t BSP_LCD_GetXSize(void) {
118     return ltdc_handle.LayerCfg[active_layer].ImageWidth;
119 }
120 
121 /**
122   * @brief  Gets the LCD Y size.
123   * @retval Used LCD Y size
124   */
BSP_LCD_GetYSize(void)125 static uint32_t BSP_LCD_GetYSize(void) {
126     return ltdc_handle.LayerCfg[active_layer].ImageHeight;
127 }
128 
BSP_LCD_PixelSize(void)129 static size_t BSP_LCD_PixelSize(void) {
130     return (ltdc_handle.LayerCfg[active_layer].PixelFormat ==
131             LTDC_PIXEL_FORMAT_ARGB8888) ? 4 : 2;
132 }
133 
134 /**
135   * @brief  Initializes the LCD layer in ARGB8888 format (32 bits per pixel).
136   * @param  LayerIndex: Layer foreground or background
137   * @param  FB_Address: Layer frame buffer
138   * @retval None
139   */
BSP_LCD_LayerDefaultInit(uint16_t LayerIndex,uint32_t FB_Address)140 static void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) {
141     LCD_LayerCfgTypeDef  layer_cfg;
142 
143     /* Layer Init */
144     layer_cfg.WindowX0 = 0;
145     layer_cfg.WindowX1 = BSP_LCD_GetXSize();
146     layer_cfg.WindowY0 = 0;
147     layer_cfg.WindowY1 = BSP_LCD_GetYSize();
148     layer_cfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;
149     layer_cfg.FBStartAdress = FB_Address;
150     layer_cfg.Alpha = 255;
151     layer_cfg.Alpha0 = 0;
152     layer_cfg.Backcolor.Blue = 0;
153     layer_cfg.Backcolor.Green = 0;
154     layer_cfg.Backcolor.Red = 0;
155     layer_cfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
156     layer_cfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
157     layer_cfg.ImageWidth = BSP_LCD_GetXSize();
158     layer_cfg.ImageHeight = BSP_LCD_GetYSize();
159 
160     HAL_LTDC_ConfigLayer(&ltdc_handle, &layer_cfg, LayerIndex);
161 }
162 
163 /**
164   * @brief  Selects the LCD Layer.
165   * @param  LayerIndex: Layer foreground or background
166   * @retval None
167   */
BSP_LCD_SelectLayer(uint32_t LayerIndex)168 void BSP_LCD_SelectLayer(uint32_t LayerIndex) {
169     active_layer = LayerIndex;
170 }
171 
172 /**
173   * @brief  Sets an LCD Layer visible
174   * @param  LayerIndex: Visible Layer
175   * @param  State: New state of the specified layer
176   *          This parameter can be one of the following values:
177   *            @arg  ENABLE
178   *            @arg  DISABLE
179   * @retval None
180   */
BSP_LCD_SetLayerVisible(uint32_t LayerIndex,FunctionalState State)181 void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State) {
182     if (State == ENABLE) {
183         __HAL_LTDC_LAYER_ENABLE(&ltdc_handle, LayerIndex);
184     } else {
185         __HAL_LTDC_LAYER_DISABLE(&ltdc_handle, LayerIndex);
186     }
187     __HAL_LTDC_RELOAD_CONFIG(&ltdc_handle);
188 }
189 
190 /**
191   * @brief  Sets an LCD layer frame buffer address.
192   * @param  LayerIndex: Layer foreground or background
193   * @param  Address: New LCD frame buffer value
194   * @retval None
195   */
BSP_LCD_SetLayerAddress(uint32_t LayerIndex,uint32_t Address)196 void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) {
197     HAL_LTDC_SetAddress(&ltdc_handle, Address, LayerIndex);
198 }
199 
200 /**
201   * @brief  Enables the display.
202   * @retval None
203   */
BSP_LCD_DisplayOn(void)204 void BSP_LCD_DisplayOn(void) {
205     /* Display On */
206     __HAL_LTDC_ENABLE(&ltdc_handle);
207     HAL_GPIO_WritePin(LCD_DISP_GPIO_PORT, LCD_DISP_PIN, GPIO_PIN_SET);
208     HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_SET);
209 }
210 
211 /**
212   * @brief  Disables the display.
213   * @retval None
214   */
BSP_LCD_DisplayOff(void)215 void BSP_LCD_DisplayOff(void) {
216     /* Display Off */
217     __HAL_LTDC_DISABLE(&ltdc_handle);
218     HAL_GPIO_WritePin(LCD_DISP_GPIO_PORT, LCD_DISP_PIN, GPIO_PIN_RESET);
219     HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_RESET);
220 }
221 
222 /**
223   * @brief  Initializes the LTDC MSP.
224   * @param  hltdc: LTDC handle
225   * @param  Params
226   * @retval None
227   */
BSP_LCD_MspInit(LTDC_HandleTypeDef * hltdc,void * Params)228 static void BSP_LCD_MspInit(LTDC_HandleTypeDef *hltdc, void *Params) {
229     GPIO_InitTypeDef gpio_init_structure;
230 
231     /* Enable the LTDC and DMA2D clocks */
232     __HAL_RCC_LTDC_CLK_ENABLE();
233     __HAL_RCC_DMA2D_CLK_ENABLE();
234 
235     /* Enable GPIOs clock */
236     __HAL_RCC_GPIOE_CLK_ENABLE();
237     __HAL_RCC_GPIOG_CLK_ENABLE();
238     __HAL_RCC_GPIOI_CLK_ENABLE();
239     __HAL_RCC_GPIOJ_CLK_ENABLE();
240     __HAL_RCC_GPIOK_CLK_ENABLE();
241     LCD_DISP_GPIO_CLK_ENABLE();
242     LCD_BL_CTRL_GPIO_CLK_ENABLE();
243 
244     /*** LTDC Pins configuration ***/
245     /* GPIOE configuration */
246     gpio_init_structure.Pin       = GPIO_PIN_4;
247     gpio_init_structure.Mode      = GPIO_MODE_AF_PP;
248     gpio_init_structure.Pull      = GPIO_NOPULL;
249     gpio_init_structure.Speed     = GPIO_SPEED_FAST;
250     gpio_init_structure.Alternate = GPIO_AF14_LTDC;
251     HAL_GPIO_Init(GPIOE, &gpio_init_structure);
252 
253     /* GPIOG configuration */
254     gpio_init_structure.Pin       = GPIO_PIN_12;
255     gpio_init_structure.Mode      = GPIO_MODE_AF_PP;
256     gpio_init_structure.Alternate = GPIO_AF9_LTDC;
257     HAL_GPIO_Init(GPIOG, &gpio_init_structure);
258 
259     /* GPIOI LTDC alternate configuration */
260     gpio_init_structure.Pin       = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | \
261                                     GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
262     gpio_init_structure.Mode      = GPIO_MODE_AF_PP;
263     gpio_init_structure.Alternate = GPIO_AF14_LTDC;
264     HAL_GPIO_Init(GPIOI, &gpio_init_structure);
265 
266     /* GPIOJ configuration */
267     gpio_init_structure.Pin       = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \
268                                     GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \
269                                     GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \
270                                     GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
271     gpio_init_structure.Mode      = GPIO_MODE_AF_PP;
272     gpio_init_structure.Alternate = GPIO_AF14_LTDC;
273     HAL_GPIO_Init(GPIOJ, &gpio_init_structure);
274 
275     /* GPIOK configuration */
276     gpio_init_structure.Pin       = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | \
277                                     GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
278     gpio_init_structure.Mode      = GPIO_MODE_AF_PP;
279     gpio_init_structure.Alternate = GPIO_AF14_LTDC;
280     HAL_GPIO_Init(GPIOK, &gpio_init_structure);
281 
282     /* LCD_DISP GPIO configuration
283        Note that LCD_DISP pin has to be manually controlled.
284      */
285     gpio_init_structure.Pin       = LCD_DISP_PIN;
286     gpio_init_structure.Mode      = GPIO_MODE_OUTPUT_PP;
287     HAL_GPIO_Init(LCD_DISP_GPIO_PORT, &gpio_init_structure);
288 
289     /* LCD_BL_CTRL GPIO configuration
290        Note that LCD_BL_CTRL pin has to be manually controlled.
291      */
292     gpio_init_structure.Pin       = LCD_BL_CTRL_PIN;
293     gpio_init_structure.Mode      = GPIO_MODE_OUTPUT_PP;
294     HAL_GPIO_Init(LCD_BL_CTRL_GPIO_PORT, &gpio_init_structure);
295 }
296 
297 /**
298   * @brief  Clock Config.
299   * @param  hltdc: LTDC handle
300   * @param  Params
301   * @note   This API is called by BSP_LCD_Init()
302   * @retval None
303   */
BSP_LCD_ClockConfig(LTDC_HandleTypeDef * hltdc,void * Params)304 static void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params) {
305     static RCC_PeriphCLKInitTypeDef  periph_clk_init_struct;
306 
307     /* RK043FN48H LCD clock configuration */
308     /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
309     /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */
310     /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/5 = 38.4 Mhz */
311     /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_4 = 38.4/4 = 9.6Mhz */
312     periph_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
313     periph_clk_init_struct.PLLSAI.PLLSAIN = 192;
314     periph_clk_init_struct.PLLSAI.PLLSAIR = RK043FN48H_FREQUENCY_DIVIDER;
315     periph_clk_init_struct.PLLSAIDivR = RCC_PLLSAIDIVR_4;
316     HAL_RCCEx_PeriphCLKConfig(&periph_clk_init_struct);
317 }
318 
319 /**
320   * @brief  Initializes the LCD.
321   * @retval LCD state
322   */
BSP_LCD_Init(void)323 uint8_t BSP_LCD_Init(void) {
324     /* Timing Configuration */
325     ltdc_handle.Init.HorizontalSync = (RK043FN48H_HSYNC - 1);
326     ltdc_handle.Init.VerticalSync = (RK043FN48H_VSYNC - 1);
327     ltdc_handle.Init.AccumulatedHBP = (RK043FN48H_HSYNC + RK043FN48H_HBP - 1);
328     ltdc_handle.Init.AccumulatedVBP = (RK043FN48H_VSYNC + RK043FN48H_VBP - 1);
329     ltdc_handle.Init.AccumulatedActiveH = (RK043FN48H_HEIGHT + RK043FN48H_VSYNC + RK043FN48H_VBP - 1);
330     ltdc_handle.Init.AccumulatedActiveW = (RK043FN48H_WIDTH + RK043FN48H_HSYNC + RK043FN48H_HBP - 1);
331     ltdc_handle.Init.TotalHeigh = (RK043FN48H_HEIGHT + RK043FN48H_VSYNC + RK043FN48H_VBP + RK043FN48H_VFP - 1);
332     ltdc_handle.Init.TotalWidth = (RK043FN48H_WIDTH + RK043FN48H_HSYNC + RK043FN48H_HBP + RK043FN48H_HFP - 1);
333 
334     /* LCD clock configuration */
335     BSP_LCD_ClockConfig(&ltdc_handle, NULL);
336 
337     /* Initialize the LCD pixel width and pixel height */
338     ltdc_handle.LayerCfg->ImageWidth  = RK043FN48H_WIDTH;
339     ltdc_handle.LayerCfg->ImageHeight = RK043FN48H_HEIGHT;
340 
341     /* Background value */
342     ltdc_handle.Init.Backcolor.Blue = 0;
343     ltdc_handle.Init.Backcolor.Green = 0;
344     ltdc_handle.Init.Backcolor.Red = 0;
345 
346     /* Polarity */
347     ltdc_handle.Init.HSPolarity = LTDC_HSPOLARITY_AL;
348     ltdc_handle.Init.VSPolarity = LTDC_VSPOLARITY_AL;
349     ltdc_handle.Init.DEPolarity = LTDC_DEPOLARITY_AL;
350     ltdc_handle.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
351     ltdc_handle.Instance = LTDC;
352 
353     if (HAL_LTDC_GetState(&ltdc_handle) == HAL_LTDC_STATE_RESET) {
354         BSP_LCD_MspInit(&ltdc_handle, NULL);
355     }
356 
357     HAL_LTDC_Init(&ltdc_handle);
358 
359     /* allocate the framebuffer */
360     size_t fb_size_pages = PAGE_ALIGN(RK043FN48H_WIDTH * RK043FN48H_HEIGHT * 4) / PAGE_SIZE;
361     void *fb_address = novm_alloc_pages(fb_size_pages, NOVM_ARENA_SECONDARY);
362     if (!fb_address)
363         panic("failed to allocate framebuffer for LCD\n");
364 
365     BSP_LCD_LayerDefaultInit(0, (uint32_t)fb_address);
366     BSP_LCD_SelectLayer(0);
367 
368     /* clear framebuffer */
369     memset((void *)ltdc_handle.LayerCfg[active_layer].FBStartAdress, 0,
370            BSP_LCD_GetXSize() * BSP_LCD_GetYSize() * BSP_LCD_PixelSize());
371 
372     /* turn the display on */
373     BSP_LCD_DisplayOn();
374     return LCD_OK;
375 }
376 
377 /* LK display (lib/gfx.h) calls this function */
display_get_framebuffer(struct display_framebuffer * fb)378 status_t display_get_framebuffer(struct display_framebuffer *fb) {
379     fb->image.pixels = (void *)ltdc_handle.LayerCfg[active_layer].FBStartAdress;
380 
381     if (ltdc_handle.LayerCfg[active_layer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) {
382         fb->format = DISPLAY_FORMAT_ARGB_8888;
383         fb->image.format = IMAGE_FORMAT_ARGB_8888;
384         fb->image.rowbytes = BSP_LCD_GetXSize() * 4;
385     } else if (ltdc_handle.LayerCfg[active_layer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) {
386         fb->format = DISPLAY_FORMAT_RGB_565;
387         fb->image.format = IMAGE_FORMAT_RGB_565;
388         fb->image.rowbytes = BSP_LCD_GetXSize() * 2;
389     } else {
390         panic("unhandled pixel format\n");
391         return ERR_NOT_FOUND;
392     }
393 
394     fb->image.width = BSP_LCD_GetXSize();
395     fb->image.height = BSP_LCD_GetYSize();
396     fb->image.stride = BSP_LCD_GetXSize();
397     fb->flush = NULL;
398 
399     return NO_ERROR;
400 }
401 
display_get_info(struct display_info * info)402 status_t display_get_info(struct display_info *info) {
403     if (ltdc_handle.LayerCfg[active_layer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) {
404         info->format = DISPLAY_FORMAT_ARGB_8888;
405     } else if (ltdc_handle.LayerCfg[active_layer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) {
406         info->format = DISPLAY_FORMAT_RGB_565;
407     } else {
408         panic("unhandled pixel format\n");
409         return ERR_NOT_FOUND;
410     }
411 
412     info->width = BSP_LCD_GetXSize();
413     info->height = BSP_LCD_GetYSize();
414 
415     return NO_ERROR;
416 }
417 
display_present(struct display_image * image,uint starty,uint endy)418 status_t display_present(struct display_image *image, uint starty, uint endy) {
419     TRACEF("display_present - not implemented");
420     DEBUG_ASSERT(false);
421     return NO_ERROR;
422 }
423