1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020/12/31     Bernard      Add license info
9  */
10 #include <stdint.h>
11 #include <string.h>
12 #include <stdlib.h>
13 
14 #include <rtthread.h>
15 #ifdef RT_USING_SMART
16 #include <lwp.h>
17 #include <lwp_user_mm.h>
18 #endif
19 #include <board.h>
20 
21 #include "drv_clcd.h"
22 #include "rt_lcd.h"
23 
24 #define CLCD_WIDTH  (BSP_LCD_WIDTH)
25 #define CLCD_HEIGHT (BSP_LCD_HEIGHT)
26 
27 #define CLCD_DEVICE(dev)    (struct drv_clcd_device*)(dev)
28 
29 #define PL111_CR_EN         0x001
30 #define PL111_CR_PWR        0x800
31 #define PL111_IOBASE        0x10020000
32 #define PL111_PALBASE       (PL111_IOBASE + 0x200)
33 
34 typedef struct _PL111MMIO
35 {
36     uint32_t      volatile tim0;      //0
37     uint32_t      volatile tim1;      //4
38     uint32_t      volatile tim2;      //8
39     uint32_t      volatile tim3;      //c
40     uint32_t      volatile upbase;    //10
41     uint32_t      volatile f;         //14
42     uint32_t      volatile control;   //18
43     uint32_t      volatile g;         //1c
44 } PL111MMIO;
45 
46 struct drv_clcd_device
47 {
48     struct rt_device parent;
49 
50     int width;
51     int height;
52 
53     uint8_t *fb;
54 };
55 struct drv_clcd_device _lcd;
56 
drv_clcd_init(struct rt_device * device)57 static rt_err_t drv_clcd_init(struct rt_device *device)
58 {
59     struct drv_clcd_device *lcd = CLCD_DEVICE(device);
60 
61     (void)lcd; /* nothing, right now */
62     return RT_EOK;
63 }
64 
drv_clcd_control(struct rt_device * device,int cmd,void * args)65 static rt_err_t drv_clcd_control(struct rt_device *device, int cmd, void *args)
66 {
67     struct drv_clcd_device *lcd = CLCD_DEVICE(device);
68 
69     switch (cmd)
70     {
71     case RTGRAPHIC_CTRL_RECT_UPDATE:
72         {
73             struct rt_device_rect_info *info = (struct rt_device_rect_info*)args;
74 
75             info = info; /* nothing, right now */
76         }
77         break;
78 
79     case RTGRAPHIC_CTRL_GET_INFO:
80         {
81             struct rt_device_graphic_info* info = (struct rt_device_graphic_info*)args;
82 
83             RT_ASSERT(info != RT_NULL);
84             info->pixel_format  = RTGRAPHIC_PIXEL_FORMAT_RGB565;
85             info->bits_per_pixel= 16;
86             info->width         = lcd->width;
87             info->height        = lcd->height;
88             info->framebuffer   = lcd->fb;
89         }
90         break;
91 
92     case FBIOGET_FSCREENINFO:
93     {
94 #ifdef RT_USING_SMART
95         struct fb_fix_screeninfo *info = (struct fb_fix_screeninfo *)args;
96         strncpy(info->id, "lcd", sizeof(info->id));
97         info->smem_len    = lcd->width * lcd->height * 2;
98         info->smem_start  = (uint32_t)lwp_map_user_phy(lwp_self(), RT_NULL, lcd->fb,
99             info->smem_len, 1);
100         info->line_length = lcd->width * 2;
101 #endif
102     }
103         break;
104 
105     case FBIOGET_VSCREENINFO:
106     {
107         struct fb_var_screeninfo *info = (struct fb_var_screeninfo *)args;
108         info->bits_per_pixel = 16;
109         info->xres = lcd->width;
110         info->yres = lcd->height;
111     }
112         break;
113 
114     case FBIOGET_DISPINFO:
115         break;
116     }
117 
118     return RT_EOK;
119 }
120 
121 #ifdef RT_USING_DEVICE_OPS
122 const static struct rt_device_ops clcd_ops =
123 {
124     drv_clcd_init,
125     RT_NULL,
126     RT_NULL,
127     RT_NULL,
128     RT_NULL,
129     drv_clcd_control
130 };
131 #endif
132 
drv_clcd_hw_init(void)133 int drv_clcd_hw_init(void)
134 {
135     PL111MMIO   *plio;
136     struct rt_device *device = &_lcd.parent;
137 
138     /* memset _lcd to zero */
139     memset(&_lcd, 0x0, sizeof(_lcd));
140 
141     _lcd.width  = CLCD_WIDTH;
142     _lcd.height = CLCD_HEIGHT;
143     rt_kprintf("try to allocate fb... | w - %d, h - %d | ", _lcd.width, _lcd.height);
144 #ifdef RT_USING_SMART
145     _lcd.fb = rt_pages_alloc(rt_page_bits(_lcd.width * _lcd.height * 2));
146 #else
147     _lcd.fb = rt_malloc(_lcd.width * _lcd.height * 2);
148 #endif
149     rt_kprintf("done!\n");
150     rt_kprintf("fb => 0x%08x\n", _lcd.fb);
151     if (_lcd.fb == NULL)
152     {
153         rt_kprintf("initialize frame buffer failed!\n");
154         return -1;
155     }
156     memset(_lcd.fb, 0xff, _lcd.width * _lcd.height * 2);
157 
158     plio = (PL111MMIO*)PL111_IOBASE;
159 #ifdef RT_USING_SMART
160     plio = (PL111MMIO *)rt_ioremap((void*)PL111_IOBASE, 0x1000);
161 #endif
162     plio->tim0 = 0x3F1F3C00 | ((CLCD_WIDTH / 16 - 1) << 2);
163     plio->tim1 = 0x080B6000 | (CLCD_HEIGHT - 1);
164 
165     plio->upbase = (uint32_t)_lcd.fb;
166 #ifdef RT_USING_SMART
167     plio->upbase += PV_OFFSET;
168 #endif
169     /* 16-bit 565 color */
170     plio->control = 0x1921 | (0x6 << 1);
171 
172     device->type    = RT_Device_Class_Graphic;
173 #ifdef RT_USING_DEVICE_OPS
174     device->ops     = &clcd_ops;
175 #else
176     device->init    = drv_clcd_init;
177     device->control = drv_clcd_control;
178 #endif
179 
180     rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR);
181 
182     return 0;
183 }
184 INIT_DEVICE_EXPORT(drv_clcd_hw_init);
185