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