]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/arm_drivers/lcd/src/lcd-omap3.c
501ff6f4ba0d66d8775ad70291a1e635d1765b09
[l4.git] / l4 / pkg / arm_drivers / lcd / src / lcd-omap3.c
1 /*
2  * OMAP3 CLCD driver
3  */
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8
9 #include <l4/arm_drivers/lcd.h>
10 #include <l4/io/io.h>
11 #include <l4/re/c/dataspace.h>
12 #include <l4/re/c/mem_alloc.h>
13 #include <l4/re/c/namespace.h>
14 #include <l4/re/c/rm.h>
15 #include <l4/re/c/util/cap_alloc.h>
16 #include <l4/util/util.h>
17 #include <l4/vbus/vbus.h>
18 #include <l4/vbus/vbus_gpio.h>
19 #include <l4/vbus/vbus_i2c.h>
20
21 #include "lcd-omap3.h"
22
23 enum {
24   /* Beagleboard mode assumes that U-Boot has set up everything and we
25    * basically just need to set the framebuffer address */
26   MODE_BEAGLEBOARD = 0,
27   MODE_EVM = 1,
28 };
29
30 static int lcd_mode;
31
32 static inline int is_omap3evm(void)    { return lcd_mode == MODE_EVM; }
33 static inline int is_beagleboard(void) { return lcd_mode == MODE_BEAGLEBOARD; }
34
35 static inline int width(void)
36 {
37   if (is_omap3evm())
38     return 480;
39   if (is_beagleboard())
40     return 1280;
41   return 0;
42 }
43
44 static inline int height(void)
45 {
46   if (is_omap3evm())
47     return 640;
48   if (is_beagleboard())
49     return 720;
50   return 0;
51 }
52
53 static inline int bytes_per_pixel(void)
54 { return 2; }
55
56 static unsigned int fbmem_size(void)
57 { return height() * width() * bytes_per_pixel(); }
58
59
60 static l4_addr_t omap_dss_virt_base;
61 static void *fb_vaddr;
62 static l4_addr_t fb_paddr;
63 static l4_cap_idx_t vbus = L4_INVALID_CAP;
64 static l4vbus_device_handle_t i2c_handle;
65 static l4vbus_device_handle_t gpio_handle;
66
67 static l4_umword_t read_dss_reg(unsigned reg)
68 {
69   return *((volatile l4_umword_t *)(omap_dss_virt_base + reg));
70 }
71
72 static void write_dss_reg(unsigned reg, l4_umword_t val)
73 {
74   *((volatile l4_umword_t *)(omap_dss_virt_base + reg)) = val;
75 }
76
77 static int disable_dss(void)
78 {
79   l4_umword_t val = read_dss_reg(Reg_dispc_control);
80
81   /* check if digital output or the lcd output are enabled */
82   if (val & (Dispc_control_digitalenable | Dispc_control_lcdenable))
83     {
84       /*Disable the lcd output and digital output*/
85       val &= ~(Dispc_control_digitalenable | Dispc_control_lcdenable);
86       write_dss_reg(Reg_dispc_control, val);
87       write_dss_reg(Reg_dispc_irqstatus, Dispc_irqstatus_framedone);
88
89       l4_usleep(100);
90       if (!(read_dss_reg(Reg_dispc_irqstatus) & Dispc_irqstatus_framedone))
91         {
92           printf("OMAP LCD: Disable DSS timeout.\n");
93           return -1;
94         }
95     }
96   return 0;
97 }
98
99 static void reset_display_controller(void)
100 {
101   disable_dss();
102
103   /* Reset the display controller. */
104   write_dss_reg(Reg_dispc_sysconfig, Dispc_sysconfig_softreset);
105
106   /* Wait until reset completes OR timeout occurs. */
107   l4_usleep(100);
108   if (!(read_dss_reg(Reg_dispc_sysstatus) & Dispc_sysstatus_resetdone))
109     {
110       printf("[LCD]: Warning: Reset DISPC timeout.\n");
111     }
112
113   l4_uint32_t reg_val = read_dss_reg(Reg_dispc_sysconfig);
114   reg_val &= ~Dispc_sysconfig_softreset;
115   write_dss_reg(Reg_dispc_sysconfig, reg_val);
116 }
117
118 static int enable_lcd_backlight(void)
119 {
120   l4_uint8_t val;
121
122   val = 0x32;
123   if (l4vbus_i2c_write(vbus, i2c_handle, T2_I2C_LED_ADDR_GROUP, TRITON2_LED_LEDEN_REG, &val, 1))
124     return -1;
125
126   val = 0x7f;
127   if (l4vbus_i2c_write(vbus, i2c_handle, T2_I2C_LED_ADDR_GROUP, TRITON2_LED_PWMAON_REG, &val, 1))
128     return -1;
129
130   val = 0x7f;
131   if (l4vbus_i2c_write(vbus, i2c_handle, T2_I2C_LED_ADDR_GROUP, TRITON2_LED_PWMBON_REG, &val, 1))
132     return -1;
133
134   val = 0x7f;
135   if (l4vbus_i2c_write(vbus, i2c_handle, T2_I2C_LED_ADDR_GROUP, TRITON2_LED_PWMAOFF_REG, &val, 1))
136     return -1;
137
138   val = 0x7f;
139   if (l4vbus_i2c_write(vbus, i2c_handle, T2_I2C_LED_ADDR_GROUP, TRITON2_LED_PWMBOFF_REG, &val, 1))
140     return -1;
141
142   val = 0x0b;
143   if (l4vbus_i2c_write(vbus, i2c_handle, 0x4b, TRITON2_VDAC_DEDICATED, &val, 1))
144     return -1;
145
146   val = 0xe0;
147   if (l4vbus_i2c_write(vbus, i2c_handle, 0x4b, TRITON2_VDAC_DEV_GRP, &val, 1))
148     return -1;
149
150   return 0;
151 }
152
153 static int enable_lcd_power(void)
154 {
155   if (l4vbus_gpio_write(vbus, gpio_handle, GPIO_NUM_VDD, 0))
156     return -1;
157   return 0;
158 }
159
160 #if 0
161 static int disable_lcd_power(void)
162 {
163   if (l4vbus_gpio_write(vbus, GPIO_NUM_VDD, 1))
164     return -1;
165   return 0;
166 }
167 #endif
168
169 static int configure_vga_mode(void)
170 {
171   if (l4vbus_gpio_write(vbus, gpio_handle, GPIO_NUM_QVGA_nVGA, 0))
172     return -1;
173   return 0;
174 }
175
176 static int configure_vert_scan_direction(int direction)
177 {
178   if (l4vbus_gpio_write(vbus, gpio_handle, GPIO_NUM_UD, direction))
179     return -1;
180   return 0;
181 }
182
183 static int configure_horiz_scan_direction(int direction)
184 {
185   if (l4vbus_gpio_write(vbus, gpio_handle, GPIO_NUM_LR, direction))
186     return -1;
187   return 0;
188 }
189
190 static int disable_lcd_reset(void)
191 {
192   if (l4vbus_gpio_write(vbus, gpio_handle, GPIO_NUM_RESB, 0))
193     return -1;
194   l4_usleep(100);
195   return 0;
196 }
197
198 static int enable_lcd_HVIF(void)
199 {
200   l4_umword_t val = read_dss_reg(Reg_dispc_pol_freq);
201   val |= ((0 << Dispc_pol_freq_rf_shift) |
202           (1 << Dispc_pol_freq_onoff_shift));
203   write_dss_reg(Reg_dispc_pol_freq, val);
204
205   return 0;
206 }
207
208 static int enable_lcd_reset(void)
209 {
210   if (l4vbus_gpio_write(vbus, gpio_handle, GPIO_NUM_RESB, 1))
211     return -1;
212   return 0;
213 }
214
215 static int enable_INI(void)
216 {
217   if (l4vbus_gpio_write(vbus, gpio_handle, GPIO_NUM_INI, 1))
218     return -1;
219   return 0;
220 }
221
222 #if 0
223 static int disble_INI(void)
224 {
225   if (l4vbus_gpio_write(vbus, GPIO_NUM_INI, 0))
226     return -1;
227   return 0;
228 }
229 #endif
230
231 static void issue_go_lcd(void)
232 {
233   l4_umword_t val = read_dss_reg(Reg_dispc_control);
234   val |= Dispc_control_golcd;
235   write_dss_reg(Reg_dispc_control, val);
236
237   l4_usleep(1000);
238   if (read_dss_reg(Reg_dispc_control) & Dispc_control_golcd)
239     {
240       printf("[LCD] Info: Update DISPC timeout.\n");
241     }
242 }
243
244 static void configure_dss_omap3evm(l4_addr_t frame_buffer)
245 {
246   l4_uint32_t val;
247
248   val = read_dss_reg(Reg_dss_control);
249   val &= 0xfffffffe;
250   write_dss_reg(Reg_dss_control, val);
251
252   /* No standby, No idle,mormal mode, ocp clock free running */
253   //val = Dispc_sysconfig_midlemode_nstandby | Dispc_sysconfig_sidlemode_nidle;
254   //val &= ~Dispc_sysconfig_softreset ;
255   //write_dss_reg(Reg_dispc_sysconfig, val);
256   write_dss_reg(Reg_dispc_sysconfig, 0x2015);
257
258   /* Not enabling any interrupts */
259   write_dss_reg(Reg_dispc_irqenable, 0x00);
260
261   /*  2:1 - Frame Data only loaded every frame (10) */
262   write_dss_reg(Reg_dispc_config, Dispc_config_loadmode_frdatlefr);
263
264   /* Default Color is white */
265   write_dss_reg(Reg_dispc_default_colour0, 0xffffff & Default_colour_mask);
266
267   /* Default Transparency Color is black */
268   write_dss_reg(Reg_dispc_trans_colour0, 0xffffff & Transparency_colour_mask);
269
270   /*timing logic for HSYNC signal */
271   val = (38 << Dispc_timing_h_hbp_shift) |
272         (44 << Dispc_timing_h_hfp_shift) |
273         (2 << Dispc_timing_h_hsw_shift);
274   write_dss_reg(Reg_dispc_timing_h, val);
275
276   /*timing logic for VSYNC signal */
277   val = (1 << Dispc_timing_v_vbp_shift) |
278         (2 << Dispc_timing_v_vfp_shift) |
279         (1 << Dispc_timing_v_vsw_shift) ;
280   write_dss_reg(Reg_dispc_timing_v, val);
281
282   /*signal configuration*/
283   val = read_dss_reg(Reg_dispc_pol_freq);
284   val |= (0 << Dispc_pol_freq_rf_shift) |
285          (1 << Dispc_pol_freq_onoff_shift) |
286          (1 << Dispc_pol_freq_ipc_shift) |
287          (1 << Dispc_pol_freq_ihs_shift) |
288          (1 << Dispc_pol_freq_ivs_shift); 
289   write_dss_reg(Reg_dispc_pol_freq, val);
290
291   /*configure the divisor*/ 
292   //val = (1 << Dispc_divisor_lcd_shift) | (3 << Dispc_divisor_pcd_shift);
293   //write_dss_reg(Dispc_divisor, val);
294   write_dss_reg(Reg_dispc_divisor, 0x10012);
295
296   /* Set panel size */
297   val = (((width() - 1) << Dispc_size_lcd_ppl_shift) & Dispc_size_lcd_ppl) |
298         (((height() - 1) << Dispc_size_lcd_lpp_shift) & Dispc_size_lcd_lpp);
299   write_dss_reg(Reg_dispc_size_lcd, val);
300
301   /* Set tft interface width */
302   val = read_dss_reg(Reg_dispc_control);
303   val &= ~Dispc_control_tftdatalines_oalsb16b;
304   val |= Dispc_control_tftdatalines_oalsb18b;
305   write_dss_reg(Reg_dispc_control, val);
306
307   /* Configure Graphics Window. */
308   write_dss_reg(Reg_dispc_gfx_ba0, frame_buffer);
309   write_dss_reg(Reg_dispc_gfx_ba1, frame_buffer);
310   write_dss_reg(Reg_dispc_gfx_position, 0);
311   val = (((width() - 1) << Dispc_gfx_size_ppl_shift) & Dispc_gfx_size_ppl) |
312         (((height() - 1) << Dispc_gfx_size_lpp_shift) & Dispc_gfx_size_lpp);
313   write_dss_reg(Reg_dispc_gfx_size, val);
314
315   val = read_dss_reg(Reg_dispc_gfx_attributes);
316   val |= (RGB16 << 1);
317   write_dss_reg(Reg_dispc_gfx_attributes, val);
318
319   val = (252 << Dispc_gfx_fifo_threshold_high_shift) |
320         (192 << Dispc_gfx_fifo_threshold_low_shift);
321   write_dss_reg(Reg_dispc_gfx_fifo_threshold, val);
322
323   /* Default row inc = 1. */
324   write_dss_reg(Reg_dispc_gfx_row_inc, 1);
325   /* Default pixel inc = 1. */
326   write_dss_reg(Reg_dispc_gfx_pixel_inc, 1);
327
328   /* Enable GFX pipeline */
329   val = read_dss_reg(Reg_dispc_gfx_attributes);
330   val |= Attributes_enable;
331   write_dss_reg(Reg_dispc_gfx_attributes, val);
332 }
333
334
335 static void configure_dss_beagleboard(l4_addr_t frame_buffer)
336 {
337   // for beagleboard just set the framebuffer address and let it run,
338   // everything else is already configured by U-Boot
339   write_dss_reg(Reg_dispc_gfx_ba0, frame_buffer);
340   write_dss_reg(Reg_dispc_gfx_ba1, frame_buffer);
341 }
342
343 static void configure_dss(l4_addr_t frame_buffer)
344 {
345   if (is_omap3evm())
346     configure_dss_omap3evm(frame_buffer);
347
348   if (is_beagleboard())
349     configure_dss_beagleboard(frame_buffer);
350
351   printf("[LCD] Info: Configured display controller.\n");
352 }
353
354 static void display_lcd_image(void)
355 {
356
357   if (is_omap3evm())
358     {
359       l4_umword_t val;
360       /* Lcd output enabled, active display, 16-bit output */
361       val = Dispc_control_gpout1 |
362             Dispc_control_gpout0 |
363             Dispc_control_tftdatalines_oalsb18b |
364             Dispc_control_stntft |
365             Dispc_control_lcdenable;
366       val &= ~Dispc_control_rfbimode;
367       write_dss_reg(Reg_dispc_control, val);
368     }
369
370   issue_go_lcd();
371 }
372
373 static int configure_lcd(l4_addr_t frame_buffer)
374 {
375   if (is_omap3evm())
376     {
377       reset_display_controller();
378       if (enable_lcd_backlight())
379         return -1;
380       if (enable_lcd_power())
381         return -1;
382       if (configure_vga_mode())
383         return -1;
384       disable_lcd_reset();
385       enable_lcd_HVIF();
386       enable_lcd_reset();
387       enable_INI();
388       configure_vert_scan_direction(CONV_SCAN_DIRECTION);
389       configure_horiz_scan_direction(CONV_SCAN_DIRECTION);
390     }
391
392   configure_dss(frame_buffer);
393
394   //enable_replication_logic(GFX_PIPELINE);
395   display_lcd_image();
396
397   return 0;
398 }
399
400 static
401 int clcd_init(void)
402 {
403   if (is_omap3evm())
404     {
405       vbus = l4re_get_env_cap("vbus");
406
407       if (l4_is_invalid_cap(vbus))
408         {
409           printf("[LCD] Error: Could not query <vbus> capability\n");
410           return -1;
411         }
412
413       if (l4vbus_get_device_by_hid(vbus, 0, &i2c_handle, "i2c", 0, 0))
414         {
415           printf("[LCD] Error: Could not find <i2c> vbus device\n");
416           return -1;
417         }
418
419       if (l4vbus_get_device_by_hid(vbus, 0, &gpio_handle, "gpio", 0, 0))
420         {
421           printf("[LCD] Error: Could not find <gpio> vbus device\n");
422           return -L4_ENODEV;
423         }
424     }
425
426   return configure_lcd(fb_paddr);
427 }
428
429 static void setup_memory(void)
430 {
431   int ret;
432
433   l4_size_t phys_size;
434
435   if (fb_vaddr)
436     return;
437
438   ret = l4io_request_iomem(0x48050000, 0x1000, 0, &omap_dss_virt_base);
439   if (ret)
440     {
441       printf("[LCD] Error: Could not map device memory\n");
442       return;
443     }
444   
445   // get some frame buffer
446   l4re_ds_t mem = l4re_util_cap_alloc();
447   if (l4_is_invalid_cap(mem))
448     return;
449
450   if (l4re_ma_alloc(fbmem_size(), mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED))
451     {
452       printf("[LCD] Error: Could not allocate memory\n");
453       return;
454     }
455
456   fb_vaddr = 0;
457   if (l4re_rm_attach(&fb_vaddr, fbmem_size(),
458                      L4RE_RM_SEARCH_ADDR | L4RE_RM_EAGER_MAP,
459                      mem, 0, L4_PAGESHIFT))
460     {
461       printf("[LCD] Error: Could not attach memory\n");
462       return;
463     }
464
465   printf("[LCD] Info: Video memory is at virtual %p (size: 0x%x Bytes)\n",
466          fb_vaddr, fbmem_size());
467
468   // get physical address
469   if (l4re_ds_phys(mem, 0, &fb_paddr, &phys_size)
470       || phys_size != fbmem_size())
471     {
472       printf("[LCD] Error: Could not get physical address\n");
473       return;
474     }
475   printf("[LCD] Info: Physical video memory is at %p\n", (void *)fb_paddr);
476 }
477
478
479 static int lcd_probe(const char *configstr)
480 {
481   lcd_mode = MODE_BEAGLEBOARD;
482
483   if (configstr &&
484       (strstr(configstr, "evm")
485        || strstr(configstr, "init")))
486     lcd_mode = MODE_EVM;
487
488   return !l4io_lookup_device("OMAP_LCD", NULL, 0, 0);
489 }
490
491 static void *lcd_get_fb(void)
492 {
493   if (!fb_vaddr)
494     setup_memory();
495
496   return fb_vaddr;
497 }
498
499 static unsigned int lcd_fbmem_size(void) { return fbmem_size(); }
500
501 static const char *lcd_get_info(void)
502 {
503   if (is_beagleboard())
504     return "ARM OMAP3 Beagleboard LCD";
505
506   if (is_omap3evm())
507     return "ARM OMAP3EVM LCD";
508
509   return "ARM OMAP3EVM unknown";
510 }
511
512 static int get_fbinfo(l4re_video_view_info_t *vinfo)
513 {
514   vinfo->width               = width();
515   vinfo->height              = height();
516   vinfo->bytes_per_line      = bytes_per_pixel() * vinfo->width;
517
518   vinfo->pixel_info.bytes_per_pixel = bytes_per_pixel();
519   vinfo->pixel_info.r.shift         = 0;
520   vinfo->pixel_info.r.size          = 5;
521   vinfo->pixel_info.g.shift         = 5;
522   vinfo->pixel_info.g.size          = 6;
523   vinfo->pixel_info.b.shift         = 11;
524   vinfo->pixel_info.b.size          = 5;
525   vinfo->pixel_info.a.shift         = 0;
526   vinfo->pixel_info.a.size          = 0;
527   return 0;
528 }
529
530 static void lcd_enable(void)
531 {
532   setup_memory();
533
534   if (clcd_init())
535     {
536       printf("CLCD init failed!\n");
537       return;
538     }
539 }
540
541 static void lcd_disable(void)
542 {
543   printf("%s unimplemented.\n", __func__);
544 }
545
546 static struct arm_lcd_ops arm_lcd_ops_omap3 = {
547   .probe              = lcd_probe,
548   .get_fb             = lcd_get_fb,
549   .get_fbinfo         = get_fbinfo,
550   .get_video_mem_size = lcd_fbmem_size,
551   .get_info           = lcd_get_info,
552   .enable             = lcd_enable,
553   .disable            = lcd_disable,
554 };
555
556 arm_lcd_register(&arm_lcd_ops_omap3);