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  * 2021-01-11     Lyons        first version
9  * 2021-06-24     RiceChen     refactor
10  * 2021-07-28     songchao     add cmd
11  */
12 
13 #include <rthw.h>
14 #include <rtdevice.h>
15 
16 #ifdef BSP_USING_LCD
17 
18 #define LOG_TAG              "drv.lcd"
19 #include <drv_log.h>
20 
21 #include "fsl_iomuxc.h"
22 #include "drv_lcd.h"
23 #include <lwp_user_mm.h>
24 
25 static struct imx6ull_lcd_config _lcd_config = LCD_BUS_CONFIG;
26 static struct imx6ull_lcd_bus _lcd_obj;
27 
imx6ull_elcd_init(rt_device_t device)28 static rt_err_t imx6ull_elcd_init(rt_device_t device)
29 {
30     struct imx6ull_lcd_bus *elcd_dev = RT_NULL;
31     clock_video_pll_config_t pll_config;
32     elcdif_rgb_mode_config_t lcd_config;
33 
34     RT_ASSERT(device != RT_NULL);
35 
36     elcd_dev = (struct imx6ull_lcd_bus *)device;
37     ELCDIF_Reset(elcd_dev->config->ELCDIF);
38     pll_config.loopDivider = 32;
39     pll_config.postDivider = LCD_PLL_DIV;
40 
41     pll_config.numerator   = 0;
42     pll_config.denominator = 0;
43 
44     CLOCK_InitVideoPll(&pll_config);
45 
46     lcd_config.hfp           = LCD_HFP;
47     lcd_config.vfp           = LCD_VFP;
48     lcd_config.hbp           = LCD_HBP;
49     lcd_config.vbp           = LCD_VBP;
50     lcd_config.hsw           = LCD_HSW;
51     lcd_config.vsw           = LCD_VSW;
52 
53     lcd_config.polarityFlags = kELCDIF_DataEnableActiveHigh  |
54                                kELCDIF_VsyncActiveLow      |
55                                kELCDIF_HsyncActiveLow      |
56                                kELCDIF_DriveDataOnRisingClkEdge;
57 
58     switch(elcd_dev->info.pixel_format)
59     {
60         case RTGRAPHIC_PIXEL_FORMAT_RGB888:
61             lcd_config.pixelFormat = kELCDIF_PixelFormatRGB888;
62             break;
63         case RTGRAPHIC_PIXEL_FORMAT_RGB565:
64             lcd_config.pixelFormat = kELCDIF_PixelFormatRGB565;
65             break;
66         default:
67             LOG_E("not support this pixel_format %d\n",elcd_dev->info.pixel_format);
68             return RT_ERROR;
69     }
70 
71     lcd_config.panelWidth    = elcd_dev->info.width;
72     lcd_config.panelHeight   = elcd_dev->info.height;
73     lcd_config.bufferAddr    = (uint32_t)elcd_dev->fb_phy;
74     lcd_config.dataBus       = kELCDIF_DataBus24Bit;
75 
76     ELCDIF_RgbModeInit(elcd_dev->config->ELCDIF, &lcd_config);
77     ELCDIF_RgbModeStart(elcd_dev->config->ELCDIF);
78 
79     return RT_EOK;
80 }
imx6ull_elcd_control(rt_device_t device,int cmd,void * args)81 static rt_err_t imx6ull_elcd_control(rt_device_t device, int cmd, void *args)
82 {
83     struct imx6ull_lcd_bus *elcd_dev = RT_NULL;
84     int mem_size = 0;
85 
86     RT_ASSERT(device != RT_NULL);
87 
88     elcd_dev = (struct imx6ull_lcd_bus *)device;
89     switch(cmd)
90     {
91         case RTGRAPHIC_CTRL_RECT_UPDATE:
92         {
93             mem_size = elcd_dev->info.width * elcd_dev->info.height * elcd_dev->info.bits_per_pixel / 8;
94             rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void *)(_lcd_obj.info.framebuffer), mem_size);
95             break;
96         }
97         case RTGRAPHIC_CTRL_POWERON:
98         {
99             rt_pin_write(IMX6ULL_LCD_BL_PIN, PIN_HIGH);
100             break;
101         }
102         case RTGRAPHIC_CTRL_POWEROFF:
103         {
104             rt_pin_write(IMX6ULL_LCD_BL_PIN, PIN_LOW);
105             break;
106         }
107         case RTGRAPHIC_CTRL_GET_INFO:
108         {
109             struct lcd_info *info = (struct lcd_info *)args;
110             RT_ASSERT(info != RT_NULL);
111             rt_memcpy(&info->graphic, &elcd_dev->info, sizeof(struct rt_device_graphic_info));
112             info->screen.shamem_len = elcd_dev->info.width * elcd_dev->info.height * elcd_dev->info.bits_per_pixel / 8;
113             info->screen.shamem_start = (rt_uint32_t)lwp_map_user_phy(lwp_self(), RT_NULL,
114                                                                         elcd_dev->fb_phy,
115                                                                         info->screen.shamem_len, 1);
116             break;
117         }
118         case RTGRAPHIC_CTRL_SET_MODE:
119         {
120             break;
121         }
122         case FBIOGET_FSCREENINFO:
123         {
124             struct fb_fix_screeninfo *info = (struct fb_fix_screeninfo *)args;
125             rt_memcpy(info->id, elcd_dev->config->name, (strlen(elcd_dev->config->name)+1));
126             info->smem_len = elcd_dev->info.width * elcd_dev->info.height * elcd_dev->info.bits_per_pixel / 8;
127             info->smem_start = (rt_uint32_t)lwp_map_user_phy(lwp_self(), RT_NULL,
128                                                                         elcd_dev->fb_phy,
129                                                                         info->smem_len, 1);
130             info->line_length = elcd_dev->info.width * 2;
131             break;
132         }
133         case FBIOGET_VSCREENINFO:
134         {
135             struct fb_var_screeninfo *info = (struct fb_var_screeninfo *)args;
136             info->bits_per_pixel = elcd_dev->info.bits_per_pixel;
137             info->xres = elcd_dev->info.width;
138             info->yres = elcd_dev->info.height;
139             break;
140         }
141 
142     }
143     return RT_EOK;
144 }
145 
146 #ifdef RT_USING_DEVICE_OPS
147 const static struct rt_device_ops elcd_ops =
148 {
149     imx6ull_elcd_init,
150     RT_NULL,
151     RT_NULL,
152     RT_NULL,
153     RT_NULL,
154     imx6ull_elcd_control,
155 };
156 #endif
157 
rt_hw_elcd_init(void)158 int rt_hw_elcd_init(void)
159 {
160     rt_err_t ret = 0;
161 
162     _lcd_config.ELCDIF       = (LCDIF_Type *)imx6ull_get_periph_vaddr((rt_uint32_t)(_lcd_config.ELCDIF));
163     _lcd_config.lcd_mux_base = (rt_uint32_t)imx6ull_get_periph_vaddr((rt_uint32_t)(_lcd_config.lcd_mux_base));
164     _lcd_config.lcd_cfg_base = (rt_uint32_t)imx6ull_get_periph_vaddr((rt_uint32_t)(_lcd_config.lcd_cfg_base));
165 
166     for(int i = 0; i < LCD_GPIO_MAX; i++)
167     {
168         IOMUXC_SetPinMux((_lcd_config.lcd_mux_base + i * 4),
169                             0x0U, 0x0U, 0x0U, (_lcd_config.lcd_cfg_base + i * 4), 0);
170         IOMUXC_SetPinConfig((_lcd_config.lcd_mux_base + i * 4),
171                             0x0U, 0x0U, 0x0U, (_lcd_config.lcd_cfg_base + i * 4), 0xB9);
172     }
173 
174     CLOCK_EnableClock(_lcd_config.apd_clk_name);
175     CLOCK_EnableClock(_lcd_config.pix_clk_name);
176 
177     _lcd_obj.config = &_lcd_config;
178 
179     _lcd_obj.fb_virt = rt_pages_alloc(rt_page_bits(LCD_BUF_SIZE));
180     _lcd_obj.fb_phy = _lcd_obj.fb_virt + PV_OFFSET;
181 
182     LOG_D("fb address => 0x%08x\n", _lcd_obj.fb_phy);
183     if(_lcd_obj.fb_phy == RT_NULL)
184     {
185         LOG_E("initialize frame buffer failed!\n");
186         return -RT_ERROR;
187     }
188 
189     _lcd_obj.info.width          = LCD_WIDTH;
190     _lcd_obj.info.height         = LCD_HEIGHT;
191     _lcd_obj.info.pixel_format   = RTGRAPHIC_PIXEL_FORMAT_RGB888;
192     _lcd_obj.info.bits_per_pixel = LCD_BITS_PER_PIXEL;
193     _lcd_obj.info.framebuffer    = (void *)_lcd_obj.fb_virt;
194 
195     _lcd_obj.parent.type = RT_Device_Class_Graphic;
196 
197 #ifdef RT_USING_DEVICE_OPS
198     _lcd_obj.parent.ops         = &elcd_ops;
199 #else
200     _lcd_obj.parent.init    = imx6ull_elcd_init;
201     _lcd_obj.parent.open    = RT_NULL;
202     _lcd_obj.parent.close   = RT_NULL;
203     _lcd_obj.parent.read    = RT_NULL;
204     _lcd_obj.parent.write   = RT_NULL;
205     _lcd_obj.parent.control = imx6ull_elcd_control;
206 #endif
207 
208     _lcd_obj.parent.user_data = (void *)&_lcd_obj.info;
209 
210     ret = rt_device_register(&_lcd_obj.parent, _lcd_obj.config->name, RT_DEVICE_FLAG_RDWR);
211 
212     /* LCD_BL */
213     rt_pin_mode(IMX6ULL_LCD_BL_PIN, PIN_MODE_OUTPUT);
214     rt_pin_write(IMX6ULL_LCD_BL_PIN, PIN_HIGH);
215 
216     rt_memset((rt_uint8_t *)_lcd_obj.fb_virt, 0xff, LCD_BUF_SIZE);
217 
218     return ret;
219 }
220 INIT_DEVICE_EXPORT(rt_hw_elcd_init);
221 
222 #endif
223 
224