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