]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/arm_drivers/lcd/src/lcd-amba.c
update
[l4.git] / l4 / pkg / arm_drivers / lcd / src / lcd-amba.c
1 /*
2  * AMBA CLCD PL110 driver
3  */
4
5 #include <l4/arm_drivers/lcd.h>
6 #include <l4/arm_drivers/amba.h>
7 #include <l4/arm_drivers/io.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include <l4/re/c/dataspace.h>
13 #include <l4/re/c/util/cap_alloc.h>
14 #include <l4/re/c/mem_alloc.h>
15 #include <l4/re/c/rm.h>
16 #include <l4/io/io.h>
17
18 #include "lcd-amba.h"
19
20 int config_do_bgr;
21 int config_request_xga;
22 int config_use_565;
23
24 enum pl11x_type
25 {
26   UNINITIALIZED, PL110, PL111, PL_UNKNOWN
27 };
28
29 static enum pl11x_type type;
30 static void *fb_vaddr;
31 static l4_addr_t fb_paddr;
32 static int is_qemu;
33 static int use_xga;
34
35
36 static void config(const char *c)
37 {
38   // this driver scans for the following:
39   //   1024: XGA mode, VGA mode otherwise
40   //   BGR:  do bgr mode instead of rgb
41   //   565: mode (if PL111 available)
42   if (!c)
43     return;
44
45   config_request_xga = strcasestr(c, "1024") != NULL;
46   config_do_bgr      = strcasestr(c, "bgr") != NULL;
47   config_use_565     = strcasestr(c, "565") != NULL;
48 }
49
50
51
52 static void set_colors(l4re_video_view_info_t *vinfo,
53                        int wr, int wg, int wb,
54                        int sr, int sg, int sb)
55 {
56   vinfo->pixel_info.r.shift = sr;
57   vinfo->pixel_info.r.size  = wr;
58   vinfo->pixel_info.g.shift = sg;
59   vinfo->pixel_info.g.size  = wg;
60   vinfo->pixel_info.b.shift = sb;
61   vinfo->pixel_info.b.size  = wb;
62
63   printf("Color mode: %d:%d:%d  %d:%d:%d\n", sr, sg, sb, wr, wg, wb);
64 }
65
66 static int get_fbinfo(l4re_video_view_info_t *vinfo)
67 {
68
69   vinfo->width                      = use_xga ? 1024 : 640;
70   vinfo->height                     = use_xga ? 768 : 480;
71   vinfo->pixel_info.bytes_per_pixel = 2;
72   vinfo->bytes_per_line             = 2 * vinfo->width;
73
74   if ((config_use_565 && type == PL111) || (is_qemu && type == PL110))
75     {
76       if (config_do_bgr)
77         set_colors(vinfo, 5, 6, 5, 11, 5, 0);
78       else
79         set_colors(vinfo, 5, 6, 5, 0, 5, 11);
80     }
81   else
82     {
83       if (config_do_bgr)
84         set_colors(vinfo, 5, 5, 5, 10, 5, 0);
85       else
86         set_colors(vinfo, 5, 5, 5, 0, 5, 10);
87     }
88
89   return 0;
90 }
91
92 static int probe(const char *c)
93 {
94   config(c);
95
96   return !l4io_lookup_device("AMBA PL110", NULL, 0, 0);
97 }
98
99 static unsigned int fbmem_size(void)
100 { return use_xga ? (1024 * 768 * 2) : (480 * 640 * 2); }
101
102 unsigned long amba_pl110_lcd_control_virt_base;
103 unsigned long amba_pl110_sys_base_virt;
104
105 static void setup_type(void)
106 {
107   uint32_t cellid, periphid;
108
109   amba_read_id(amba_pl110_lcd_control_virt_base + 0xfe0, &periphid, &cellid);
110
111   if (periphid == 0x00041111 && cellid == 0xb105f00d)
112     type = PL111;
113   else if (periphid == 0x00041110 && cellid == 0xb105f00d)
114     type = PL110;
115   else
116     type = PL_UNKNOWN;
117 }
118
119 static const char *arm_lcd_get_info(void)
120 {
121   return "ARM AMBA PrimeCell 11x";
122 }
123
124 static
125 l4_umword_t read_sys_reg(unsigned reg)
126 {
127   return io_read_mword(amba_pl110_sys_base_virt + reg);
128 }
129
130 static
131 void write_sys_reg(unsigned reg, l4_umword_t val)
132 {
133   io_write_mword(amba_pl110_sys_base_virt + reg, val);
134 }
135
136 static
137 void set_clcd_clock(l4_umword_t val)
138 {
139   write_sys_reg(Reg_sys_lock, Sys_lock_unlock);
140   write_sys_reg(Reg_sys_osc4, val);
141   write_sys_reg(Reg_sys_lock, Sys_lock_lock);
142 }
143
144 static
145 l4_umword_t read_clcd_reg(unsigned reg)
146 {
147   return *((volatile l4_umword_t *)(amba_pl110_lcd_control_virt_base + reg));
148 }
149
150 static
151 void write_clcd_reg(unsigned reg, l4_umword_t val)
152 {
153   *((volatile l4_umword_t *)(amba_pl110_lcd_control_virt_base + reg)) = val;
154 }
155
156 static
157 int init(unsigned long fb_phys_addr)
158 {
159   l4_umword_t id;
160
161   id = read_sys_reg(Reg_sys_clcd) & Sys_clcd_idmask;
162   switch (id)
163     {
164     case Sys_clcd_id84:
165     case Sys_clcd_idmask:
166     case 0x1000: // (strange?) qemu value, should be 0x100, or did they think BE?
167       printf("Configure 8.4 CLCD\n");
168       if (use_xga)
169         {
170           set_clcd_clock(Sys_osc4_xga);
171           write_clcd_reg(Reg_clcd_tim0, Clcd_tim0_84_xga);
172           write_clcd_reg(Reg_clcd_tim1, Clcd_tim1_84_xga);
173           write_clcd_reg(Reg_clcd_tim2, Clcd_tim2_84_xga);
174           write_clcd_reg(Reg_clcd_tim3, Clcd_tim3_84_xga);
175         }
176       else
177         {
178           set_clcd_clock(Sys_osc4_25mhz);
179           write_clcd_reg(Reg_clcd_tim0, Clcd_tim0_84_vga);
180           write_clcd_reg(Reg_clcd_tim1, Clcd_tim1_84_vga);
181           write_clcd_reg(Reg_clcd_tim2, Clcd_tim2_84_vga);
182           write_clcd_reg(Reg_clcd_tim3, Clcd_tim3_84_vga);
183         }
184       break;
185
186     case Sys_clcd_id38:
187       printf("Configure 3.8 CLCD\n");
188       set_clcd_clock(Sys_osc4_10mhz);
189       write_clcd_reg(Reg_clcd_tim0, Clcd_tim0_38);
190       write_clcd_reg(Reg_clcd_tim1, Clcd_tim1_38);
191       write_clcd_reg(Reg_clcd_tim2, Clcd_tim2_38);
192       write_clcd_reg(Reg_clcd_tim3, Clcd_tim3_38);
193       break;
194
195     case Sys_clcd_id25:
196       printf("Configure 2.5 CLCD\n");
197       set_clcd_clock(Sys_osc4_5p4mhz);
198       write_clcd_reg(Reg_clcd_tim0, Clcd_tim0_25);
199       write_clcd_reg(Reg_clcd_tim1, Clcd_tim1_25);
200       write_clcd_reg(Reg_clcd_tim2, Clcd_tim2_25);
201       write_clcd_reg(Reg_clcd_tim3, Clcd_tim3_25);
202
203       // Turn the backlight on
204       //write_ib2_reg(Reg_ib2_ctrl, read_ib2_reg(Reg_ib2_ctrl) | 0x01);
205       break;
206
207     default:
208       printf("Error: Unknown display type (ID: %lx)\n", id >> 8);
209       return 0;
210   }
211
212   // Set physical framebuffer address
213   write_clcd_reg(Reg_clcd_ubas, fb_phys_addr);
214   write_clcd_reg(Reg_clcd_lbas, 0);
215   write_clcd_reg(Reg_clcd_ienb, 0);
216
217   // Switch  power off and configure
218   write_clcd_reg(Reg_clcd_cntl,
219                  ((type == PL111 && config_use_565 && !is_qemu)
220                   ? Clcd_cntl_lcdbpp16_pl111_565
221                   : Clcd_cntl_lcdbpp16)
222                  | Clcd_cntl_lcden | Clcd_cntl_lcdbw
223                  | Clcd_cntl_lcdtft | Clcd_cntl_lcdvcomp
224                  | (config_do_bgr ? Clcd_cntl_lcdbgr : 0));
225
226   // Switch power on
227   write_clcd_reg(Reg_clcd_cntl, read_clcd_reg(Reg_clcd_cntl) | Clcd_cntl_lcdpwr);
228
229   return 1;
230 }
231
232 static void setup_memory(void)
233 {
234   l4_size_t phys_size;
235   l4io_device_handle_t dh;
236   l4io_resource_handle_t hdl;
237
238   if (fb_vaddr)
239     return;
240
241   if (l4io_lookup_device("System Control", &dh, 0, &hdl))
242     {
243       printf("Could not get system controller space\n");
244       return;
245     }
246
247   /* System controller -- XXX Wrong Place XXX */
248   amba_pl110_sys_base_virt
249     = l4io_request_resource_iomem(dh, &hdl);
250   if (amba_pl110_sys_base_virt == 0)
251     {
252       printf("Could not map system controller space\n");
253       return;
254     }
255
256   if (l4io_lookup_device("AMBA PL110", &dh, 0, &hdl))
257     {
258       printf("Could not get PL110 LCD device\n");
259       return;
260     }
261
262   amba_pl110_lcd_control_virt_base
263     = l4io_request_resource_iomem(dh, &hdl);
264   if (amba_pl110_lcd_control_virt_base == 0)
265     {
266       printf("Could not map controller space for '%s'\n", arm_lcd_get_info());
267       return;
268     }
269
270   setup_type();
271
272   if ((read_sys_reg(Reg_sys_clcd) & Sys_clcd_idmask) == 0x1000)
273     {
274       is_qemu = 1; // remember if we run on qemu because of the different
275                    // handling of the bpp16 mode with PL110: my hardware has
276                    // 5551 mode, qemu does 565
277       type = PL111; // also set the type to PL111 because qemu only
278                     // announces a PL110 but can do the 1024 resolution too
279       printf("Running on QEmu (assuming PL111).\n");
280     }
281
282   if (config_request_xga && type == PL111)
283     use_xga = 1;
284
285   // get some frame buffer
286   l4re_ds_t mem = l4re_util_cap_alloc();
287   if (l4_is_invalid_cap(mem))
288     return;
289
290   if (l4re_ma_alloc(fbmem_size(), mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED))
291     {
292       printf("Error allocating memory\n");
293       return;
294     }
295
296   fb_vaddr = 0;
297   if (l4re_rm_attach(&fb_vaddr, fbmem_size(),
298                      L4RE_RM_SEARCH_ADDR | L4RE_RM_EAGER_MAP,
299                      mem, 0, L4_PAGESHIFT))
300     {
301       printf("Error getting memory\n");
302       return;
303     }
304
305   printf("Video memory is at virtual %p (size: 0x%x Bytes)\n",
306          fb_vaddr, fbmem_size());
307
308   // get physical address
309   if (l4re_ds_phys(mem, 0, &fb_paddr, &phys_size)
310       || phys_size != fbmem_size())
311     {
312       printf("Getting the physical address failed or not contiguous\n");
313       return;
314     }
315   printf("Physical video memory is at %p\n", (void *)fb_paddr);
316 }
317
318 static void *fb(void)
319 {
320   if (!fb_vaddr)
321     setup_memory();
322
323   return fb_vaddr;
324 }
325
326 static void pl110_enable(void)
327 {
328   const char *s;
329
330   setup_memory();
331
332   switch (type)
333     {
334       case PL110: s = "ARM AMBA PrimeCell PL110"; break;
335       case PL111: s = "ARM AMBA PrimeCell PL111"; break;
336       default: s = "Unknown"; break;
337     }
338
339   printf("Detected a '%s' device.\n", s);
340
341   if (!fb_vaddr || !init(fb_paddr))
342     {
343       printf("CLCD init failed!\n");
344       return;
345     }
346 }
347
348 static void pl110_disable(void)
349 {
350 }
351 static struct arm_lcd_ops arm_lcd_ops_pl11x = {
352   .probe              = probe,
353   .get_fbinfo         = get_fbinfo,
354   .get_fb             = fb,
355   .get_video_mem_size = fbmem_size,
356   .get_info           = arm_lcd_get_info,
357   .enable             = pl110_enable,
358   .disable            = pl110_disable,
359 };
360
361 arm_lcd_register(&arm_lcd_ops_pl11x);