2 * Copyright 2009-2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * François Revol, revol@free.fr
7 * Alexander von Gluck IV, kallisti5@unixzen.com
11 #include "arch_framebuffer.h"
13 #include <arch/arm/omap3.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>
27 #include "graphics/omap/omap3_regs.h"
31 extern "C" addr_t
mmu_map_physical_memory(addr_t physicalAddress
, size_t size
,
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
{
45 ArchFBArmOmap3(addr_t base
)
46 : ArchFramebuffer(base
) {}
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
);
67 uint32 dispc_timing_h
;
68 uint32 dispc_timing_v
;
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
),
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
),
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
),
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
),
107 setaddr(uint32 reg
, unsigned int v
)
109 *((volatile uint32
*)(reg
)) = v
;
114 modaddr(unsigned int reg
, unsigned int m
, unsigned int v
)
118 o
= *((volatile uint32
*)(reg
));
121 *((volatile uint32
*)(reg
)) = o
;
126 void setreg(uint32 base
, unsigned int reg
, unsigned int v
)
128 *((volatile uint32
*)(base
+ reg
)) = v
;
133 uint32
readreg(uint32 base
, unsigned int reg
)
135 return *((volatile uint32
*)(base
+ reg
));
140 modreg(uint32 base
, unsigned int reg
, unsigned int m
, unsigned int v
)
144 o
= *((volatile uint32
*)(base
+ reg
));
147 *((volatile uint32
*)(base
+ reg
)) = o
;
151 // init beagle gpio for video
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?
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);
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
);
196 omap_dispc_init(void)
198 uint32 DISPC
= DISPC_BASE
;
200 setreg(DISPC
, DISPC_SYSCONFIG
,
201 DISPC_MIDLEMODE_SMART
202 | DISPC_SIDLEMODE_SMART
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
,
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
,
230 | DISPC_TFTDATALINES_24
231 | DISPC_STDITHERENABLE
237 while ((readreg(DISPC
, DISPC_CONTROL
) & DISPC_GOLCD
))
243 omap_set_lcd_mode(int w
, int h
)
245 uint32 DISPC
= DISPC_BASE
;
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
)
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
,
274 while ((readreg(DISPC
, DISPC_CONTROL
) & DISPC_GOLCD
))
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
))
307 ArchFBArmOmap3::Init()
309 gKernelArgs
.frame_buffer
.enabled
= true;
311 setreg(DISPC_BASE
, DISPC_IRQENABLE
, 0x00000);
312 setreg(DISPC_BASE
, DISPC_IRQSTATUS
, 0x1ffff);
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;
337 //dprintf("fBase %p\n", (void *)fBase);
338 if (!fBase
|| true) {
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
))
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
);
351 // TODO: More dynamic framebuffer base?
352 fPhysicalBase
= fBase
;
353 gKernelArgs
.frame_buffer
.physical_buffer
.start
= fPhysicalBase
;
356 TRACE("video mode: %ux%ux%u\n", gKernelArgs
.frame_buffer
.width
,
357 gKernelArgs
.frame_buffer
.height
, gKernelArgs
.frame_buffer
.depth
);
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
);
376 ArchFBArmOmap3::SetDefaultMode()
380 return SetVideoMode(gKernelArgs
.frame_buffer
.width
,
381 gKernelArgs
.frame_buffer
.height
,
382 gKernelArgs
.frame_buffer
.depth
);