headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / boot / arch / arm / arch_framebuffer_omap3.cpp
blob57c499f793d509884f53e91f6c2c74229009332e
1 /*
2 * Copyright 2009-2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * François Revol, revol@free.fr
7 * Alexander von Gluck IV, kallisti5@unixzen.com
8 */
11 #include "arch_framebuffer.h"
13 #include <arch/arm/omap3.h>
14 #include <arch/cpu.h>
15 #include <boot/stage2.h>
16 #include <boot/platform.h>
17 #include <boot/menu.h>
18 #include <boot/kernel_args.h>
19 #include <boot/platform/generic/video.h>
20 #include <util/list.h>
21 #include <drivers/driver_settings.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "graphics/omap/omap3_regs.h"
30 //XXX
31 extern "C" addr_t mmu_map_physical_memory(addr_t physicalAddress, size_t size,
32 uint32 flags);
33 extern "C" bool
34 mmu_get_virtual_mapping(addr_t virtualAddress, phys_addr_t *_physicalAddress);
37 #define write_io_32(a, v) ((*(vuint32 *)a) = v)
38 #define read_io_32(a) (*(vuint32 *)a)
40 #define dumpr(a) dprintf("LCC:%s:0x%lx\n", #a, read_io_32(a))
43 class ArchFBArmOmap3 : public ArchFramebuffer {
44 public:
45 ArchFBArmOmap3(addr_t base)
46 : ArchFramebuffer(base) {}
47 ~ArchFBArmOmap3() {}
49 status_t Init();
50 status_t Probe();
51 status_t SetDefaultMode();
52 status_t SetVideoMode(int width, int height, int depth);
55 extern "C" ArchFramebuffer *arch_get_fb_arm_omap3(addr_t base)
57 return new ArchFBArmOmap3(base);
61 // #pragma mark -
64 struct video_mode {
65 short width, height;
66 const char *name;
67 uint32 dispc_timing_h;
68 uint32 dispc_timing_v;
69 uint32 dispc_divisor;
70 uint32 dss_divisor;
73 // Master clock (PLL4) is 864 Mhz, and changing it is a pita since it
74 // cascades to other devices.
75 // Pixel clock is 864 / cm_clksel_dss.dss1_alwan_fclk / dispc_divisor.divisor.pcd
76 // So most of these modes are just approximate (1280x1024 is correct)
77 // List must be in ascending order.
78 struct video_mode modes[] = {
80 640, 480, "640x480-71",
81 (128 << DISPCB_HBP) | (24 << DISPCB_HFP) | (40 << DISPCB_HSW),
82 (28 << DISPCB_VBP) | (9 << DISPCB_VFP) | (3 << DISPCB_VSW),
83 2, 14
86 800, 600, "800x600-59",
87 (88 << DISPCB_HBP) | (40 << DISPCB_HFP) | (128 << DISPCB_HSW),
88 (23 << DISPCB_VBP) | (1 << DISPCB_VFP) | (4 << DISPCB_VSW),
89 2, 11
90 },
92 1024, 768, "1024x768-61",
93 (160 << DISPCB_HBP) | (24 << DISPCB_HFP) | (136 << DISPCB_HSW),
94 (29 << DISPCB_VBP) | (3 << DISPCB_VFP) | (6 << DISPCB_VSW),
95 1, 13
98 1280, 1024, "1280x1024-60",
99 (248 << DISPCB_HBP) | (48 << DISPCB_HFP) | (112 << DISPCB_HSW),
100 (38 << DISPCB_VBP) | (1 << DISPCB_VFP) | (3 << DISPCB_VSW),
101 1, 8
106 static inline void
107 setaddr(uint32 reg, unsigned int v)
109 *((volatile uint32 *)(reg)) = v;
113 static inline void
114 modaddr(unsigned int reg, unsigned int m, unsigned int v)
116 uint32 o;
118 o = *((volatile uint32 *)(reg));
119 o &= ~m;
120 o |= v;
121 *((volatile uint32 *)(reg)) = o;
125 static inline
126 void setreg(uint32 base, unsigned int reg, unsigned int v)
128 *((volatile uint32 *)(base + reg)) = v;
132 static inline
133 uint32 readreg(uint32 base, unsigned int reg)
135 return *((volatile uint32 *)(base + reg));
139 static inline void
140 modreg(uint32 base, unsigned int reg, unsigned int m, unsigned int v)
142 uint32 o;
144 o = *((volatile uint32 *)(base + reg));
145 o &= ~m;
146 o |= v;
147 *((volatile uint32 *)(base + reg)) = o;
151 // init beagle gpio for video
152 static void
153 omap_beagle_init(void)
155 // setup GPIO stuff, i can't find any references to these
156 setreg(GPIO1_BASE, GPIO_OE, 0xfefffedf);
157 setreg(GPIO1_BASE, GPIO_SETDATAOUT, 0x01000120);
158 // DVI-D is enabled by GPIO 170?
162 static void
163 omap_clock_init(void)
165 // sets pixel clock to 72MHz
167 // sys_clk = 26.0 Mhz
168 // DPLL4 = sys_clk * 432 / 13 = 864
169 // DSS1_ALWON_FCLK = 864 / 6 = 144
170 // Pixel clock (DISPC_DIVISOR) = 144 / 2 = 72Mhz
171 // and also VENC clock = 864 / 16 = 54MHz
173 // The clock multiplier/divider cannot be changed
174 // without affecting other system clocks - do don't.
176 // pll4 clock multiplier/divider
177 setaddr(CM_CLKSEL2_PLL, (432 << 8) | 12);
178 // tv clock divider, dss1 alwon fclk divider
179 setaddr(CM_CLKSEL_DSS, (16 << 8) | 6);
180 // core/peripheral PLL to 1MHz
181 setaddr(CM_CLKEN_PLL, 0x00370037);
185 static void
186 omap_dss_init(void)
188 setreg(DSS_BASE, DSS_SYSCONFIG, DSS_AUTOIDLE);
189 // Select DSS1 ALWON as clock source
190 setreg(DSS_BASE, DSS_CONTROL, DSS_VENC_OUT_SEL | DSS_DAC_POWERDN_BGZ
191 | DSS_DAC_DEMEN | DSS_VENC_CLOCK_4X_ENABLE);
195 static void
196 omap_dispc_init(void)
198 uint32 DISPC = DISPC_BASE;
200 setreg(DISPC, DISPC_SYSCONFIG,
201 DISPC_MIDLEMODE_SMART
202 | DISPC_SIDLEMODE_SMART
203 | DISPC_ENWAKEUP
204 | DISPC_AUTOIDLE);
206 setreg(DISPC, DISPC_CONFIG, DISPC_LOADMODE_FRAME);
208 // LCD default colour = black
209 setreg(DISPC, DISPC_DEFAULT_COLOR0, 0x000000);
211 setreg(DISPC, DISPC_POL_FREQ,
212 DISPC_POL_IPC
213 | DISPC_POL_IHS
214 | DISPC_POL_IVS
215 | (2<<DISPCB_POL_ACBI)
216 | (8<<DISPCB_POL_ACB));
218 // Set pixel clock divisor = 2
219 setreg(DISPC, DISPC_DIVISOR,
220 (1<<DISPCB_DIVISOR_LCD)
221 | (2<<DISPCB_DIVISOR_PCD));
223 // Disable graphical output
224 setreg(DISPC, DISPC_GFX_ATTRIBUTES, 0);
226 // Turn on the LCD output
227 setreg(DISPC, DISPC_CONTROL,
228 DISPC_GPOUT1
229 | DISPC_GPOUT0
230 | DISPC_TFTDATALINES_24
231 | DISPC_STDITHERENABLE
232 | DISPC_GOLCD
233 | DISPC_STNTFT
234 | DISPC_LCDENABLE
237 while ((readreg(DISPC, DISPC_CONTROL) & DISPC_GOLCD))
242 static void
243 omap_set_lcd_mode(int w, int h)
245 uint32 DISPC = DISPC_BASE;
246 unsigned int i;
247 struct video_mode *m;
249 dprintf("omap3: set_lcd_mode %d,%d\n", w, h);
251 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
252 if (w <= modes[i].width
253 && h <= modes[i].height)
254 goto found;
256 i -= 1;
257 found:
258 m = &modes[i];
260 dprintf("omap3: found mode[%s]\n", m->name);
262 setreg(DISPC, DISPC_SIZE_LCD, (m->width - 1) | ((m->height - 1) << 16));
263 setreg(DISPC, DISPC_TIMING_H, m->dispc_timing_h);
264 setreg(DISPC, DISPC_TIMING_V, m->dispc_timing_v);
266 modreg(DISPC, DISPC_DIVISOR, 0xffff, m->dispc_divisor);
267 modaddr(CM_CLKSEL_DSS, 0x3f, m->dss_divisor);
269 // Tell hardware to update, and wait for it
270 modreg(DISPC, DISPC_CONTROL,
271 DISPC_GOLCD,
272 DISPC_GOLCD);
274 while ((readreg(DISPC, DISPC_CONTROL) & DISPC_GOLCD))
279 static void
280 omap_attach_framebuffer(addr_t data, int width, int height, int depth)
282 uint32 DISPC = DISPC_BASE;
283 uint32 gsize = ((height - 1) << 16) | (width - 1);
285 dprintf("omap3: attach bitmap (%d,%d) to screen\n", width, height);
287 setreg(DISPC, DISPC_GFX_BA0, (uint32)data);
288 setreg(DISPC, DISPC_GFX_BA1, (uint32)data);
289 setreg(DISPC, DISPC_GFX_POSITION, 0);
290 setreg(DISPC, DISPC_GFX_SIZE, gsize);
291 setreg(DISPC, DISPC_GFX_FIFO_THRESHOLD, (0x3ff << 16) | 0x3c0);
292 setreg(DISPC, DISPC_GFX_ROW_INC, 1);
293 setreg(DISPC, DISPC_GFX_PIXEL_INC, 1);
294 setreg(DISPC, DISPC_GFX_WINDOW_SKIP, 0);
295 setreg(DISPC, DISPC_GFX_ATTRIBUTES, DISPC_GFXFORMAT_RGB16
296 | DISPC_GFXBURSTSIZE_16x32 | DISPC_GFXENABLE);
298 // Tell hardware to update, and wait for it
299 modreg(DISPC, DISPC_CONTROL, DISPC_GOLCD, DISPC_GOLCD);
301 while ((readreg(DISPC, DISPC_CONTROL) & DISPC_GOLCD))
306 status_t
307 ArchFBArmOmap3::Init()
309 gKernelArgs.frame_buffer.enabled = true;
311 setreg(DISPC_BASE, DISPC_IRQENABLE, 0x00000);
312 setreg(DISPC_BASE, DISPC_IRQSTATUS, 0x1ffff);
314 omap_beagle_init();
315 omap_clock_init();
316 omap_dss_init();
317 omap_dispc_init();
319 return B_OK;
323 status_t
324 ArchFBArmOmap3::Probe()
327 gKernelArgs.frame_buffer.depth = 16;
328 gKernelArgs.frame_buffer.width = 1024;
329 gKernelArgs.frame_buffer.height = 768;
330 gKernelArgs.frame_buffer.bytes_per_row = gKernelArgs.frame_buffer.width * 2;
331 gKernelArgs.frame_buffer.physical_buffer.size
332 = gKernelArgs.frame_buffer.width
333 * gKernelArgs.frame_buffer.height
334 * gKernelArgs.frame_buffer.depth / 8;
336 #if 1
337 //dprintf("fBase %p\n", (void *)fBase);
338 if (!fBase || true) {
339 fBase = 0;
340 int err = platform_allocate_region((void **)&fBase,
341 gKernelArgs.frame_buffer.physical_buffer.size, 0, false);
342 if (err < B_OK) return err;
343 if (!mmu_get_virtual_mapping(fBase, &fPhysicalBase))
344 return B_ERROR;
345 gKernelArgs.frame_buffer.physical_buffer.start
346 = (addr_t)fPhysicalBase;
347 dprintf("video framebuffer: va: %p pa: %p\n", (void *)fBase,
348 (void *)fPhysicalBase);
350 #else
351 // TODO: More dynamic framebuffer base?
352 fPhysicalBase = fBase;
353 gKernelArgs.frame_buffer.physical_buffer.start = fPhysicalBase;
354 #endif
356 TRACE("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width,
357 gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth);
359 return B_OK;
363 status_t
364 ArchFBArmOmap3::SetVideoMode(int width, int height, int depth)
366 TRACE("%s: %dx%d@%d\n", __func__, width, height, depth);
368 omap_set_lcd_mode(width, height);
369 omap_attach_framebuffer(fPhysicalBase, width, height, depth);
371 return B_OK;
375 status_t
376 ArchFBArmOmap3::SetDefaultMode()
378 CALLED();
380 return SetVideoMode(gKernelArgs.frame_buffer.width,
381 gKernelArgs.frame_buffer.height,
382 gKernelArgs.frame_buffer.depth);