1 /* Architecture dependent part for the framebuffer on the OMAP3.
2 * There's obvious room for improvement.
5 #include <minix/chardriver.h>
6 #include <minix/drivers.h>
8 #include <minix/type.h>
10 #include <minix/log.h>
16 #include <dev/videomode/videomode.h>
17 #include <dev/videomode/edidvar.h>
18 #include <dev/videomode/edidreg.h>
22 /* default / fallback resolution if EDID reading fails */
23 #define SCREEN_WIDTH 1024
24 #define SCREEN_HEIGHT 600
27 #define NSUPPORTED_MODES (4)
29 /* List of valid modes from TRM 7.1
30 * Other modes might work (like the default 1024x600), but no guarantees.
32 struct supported_modes
{
35 } omap_supported_modes
[NSUPPORTED_MODES
] = {
36 { .hdisplay
= 1024, .vdisplay
= 768 }, /* XGA */
37 { .hdisplay
= 1280, .vdisplay
= 800 }, /* WXGA */
38 { .hdisplay
= 1400, .vdisplay
= 1050 }, /* SXGA+ */
39 { .hdisplay
= 1280, .vdisplay
= 720 } /* HD 720p */
42 /* local function prototypes */
43 static struct videomode
*choose_mode(struct edid_info
*info
);
44 static void configure_with_defaults(int minor
);
45 static int configure_with_edid(int minor
, struct edid_info
*info
);
48 static vir_bytes dss_phys_base
; /* Address of dss phys memory map */
49 static vir_bytes dispc_phys_base
; /* Address of dispc phys memory map */
50 static vir_bytes fb_vir
;
51 static phys_bytes fb_phys
;
52 static size_t fb_size
;
53 static int initialized
= 0;
67 static const struct panel_config default_cfg
= {
68 /* See OMAP TRM section 15.7 for the register values/encoding */
69 .timing_h
= 0x1a4024c9, /* Horizontal timing */
70 .timing_v
= 0x02c00509, /* Vertical timing */
71 .pol_freq
= 0x00007028, /* Pol Freq */
72 .divisor
= 0x00010001, /* 96MHz Pixel Clock */
73 .lcd_size
= ((SCREEN_HEIGHT
- 1) << 16 | (SCREEN_WIDTH
- 1)),
74 .panel_type
= 0x01, /* TFT */
75 .data_lines
= 0x03, /* 24 Bit RGB */
76 .load_mode
= 0x02, /* Frame Mode */
77 .panel_color
= 0xFFFFFF /* WHITE */
80 static struct panel_config omap_cfg
[FB_DEV_NR
];
82 static const struct fb_fix_screeninfo default_fbfs
= {
86 .line_length
= SCREEN_WIDTH
* 4,
87 .mmio_start
= 0, /* Not implemented for char. special, so */
88 .mmio_len
= 0 /* these are set to 0 */
91 static struct fb_fix_screeninfo omap_fbfs
[FB_DEV_NR
];
93 static const struct fb_var_screeninfo default_fbvs
= {
95 .yres
= SCREEN_HEIGHT
,
96 .xres_virtual
= SCREEN_WIDTH
,
97 .yres_virtual
= SCREEN_HEIGHT
*2,
100 .bits_per_pixel
= 32,
123 static struct fb_var_screeninfo omap_fbvs
[FB_DEV_NR
];
125 /* logging - use with log_warn(), log_info(), log_debug(), log_trace() */
126 static struct log log
= {
128 .log_level
= LEVEL_INFO
,
129 .log_func
= default_log
133 readw(vir_bytes addr
)
135 return *((volatile u32_t
*) addr
);
139 writew(vir_bytes addr
, u32_t val
)
141 *((volatile u32_t
*) addr
) = val
;
144 static struct videomode
*
145 choose_mode(struct edid_info
*info
)
149 /* choose the highest resolution supported by both the SoC and screen */
150 for (i
= info
->edid_nmodes
- 1; i
>= 0; i
--) {
151 for (j
= NSUPPORTED_MODES
- 1; j
>= 0; j
--) {
153 if (info
->edid_modes
[i
].hdisplay
==
154 omap_supported_modes
[j
].hdisplay
&&
155 info
->edid_modes
[i
].vdisplay
==
156 omap_supported_modes
[j
].vdisplay
) {
158 return &(info
->edid_modes
[i
]);
167 configure_with_edid(int minor
, struct edid_info
*info
)
169 struct videomode
*mode
;
171 if (info
== NULL
|| minor
< 0 || minor
>= FB_DEV_NR
) {
172 log_warn(&log
, "Invalid minor #%d or info == NULL\n", minor
);
176 /* If debugging or tracing, print the contents of info */
177 if (log
.log_level
>= LEVEL_DEBUG
) {
178 log_debug(&log
, "--- EDID - START ---\n");
180 log_debug(&log
, "--- EDID - END ---\n");
183 /* Choose the preferred mode. */
184 mode
= choose_mode(info
);
186 log_warn(&log
, "Couldn't find a supported resolution.\n");
191 * apply the default settings since we don't overwrite every field
193 configure_with_defaults(minor
);
196 * apply the settings corresponding to the given EDID
200 omap_cfg
[minor
].lcd_size
= ((mode
->vdisplay
- 1) << 16 | (mode
->hdisplay
- 1));
202 if (EDID_FEATURES_DISP_TYPE(info
->edid_features
) ==
203 EDID_FEATURES_DISP_TYPE_MONO
) {
204 omap_cfg
[minor
].panel_type
= 0x00; /* Mono */
206 omap_cfg
[minor
].panel_type
= 0x01; /* RGB/Color */
209 /* fb_fix_screeninfo */
210 omap_fbfs
[minor
].line_length
= mode
->hdisplay
* 4;
212 /* fb_var_screeninfo */
213 omap_fbvs
[minor
].xres
= mode
->hdisplay
;
214 omap_fbvs
[minor
].yres
= mode
->vdisplay
;
215 omap_fbvs
[minor
].xres_virtual
= mode
->hdisplay
;
216 omap_fbvs
[minor
].yres_virtual
= mode
->vdisplay
*2;
222 configure_with_defaults(int minor
)
224 if (minor
< 0 || minor
>= FB_DEV_NR
) {
225 log_warn(&log
, "Invalid minor #%d\n", minor
);
229 /* copy the default values into this minor's configuration */
230 memcpy(&omap_cfg
[minor
], &default_cfg
, sizeof(struct panel_config
));
231 memcpy(&omap_fbfs
[minor
], &default_fbfs
, sizeof(struct fb_fix_screeninfo
));
232 memcpy(&omap_fbvs
[minor
], &default_fbvs
, sizeof(struct fb_var_screeninfo
));
236 arch_configure_display(int minor
)
238 /* Tell hardware where frame buffer is and turn display on */
241 if (!initialized
) return;
242 if (minor
!= 0) return;
244 off
= omap_fbvs
[minor
].yoffset
* omap_fbvs
[minor
].xres_virtual
* (omap_fbvs
[minor
].bits_per_pixel
/8);
246 writew((vir_bytes
) OMAP3_DISPC_GFX_BA0(dispc_phys_base
),
247 fb_phys
+ (phys_bytes
) off
);
248 rdispc
= readw((vir_bytes
) OMAP3_DISPC_CONTROL(dispc_phys_base
));
249 rdispc
|= DISPC_LCDENABLE
| DISPC_DIGITALENABLE
| DISPC_GOLCD
|
250 DISPC_GODIGITAL
| DISPC_GPOUT0
| DISPC_GPOUT1
;
251 writew((vir_bytes
) OMAP3_DISPC_CONTROL(dispc_phys_base
), rdispc
);
255 arch_get_device(int minor
, struct device
*dev
)
257 if (!initialized
) return ENXIO
;
258 if (minor
!= 0) return ENXIO
;
259 dev
->dv_base
= fb_vir
;
260 dev
->dv_size
= fb_size
;
265 arch_get_varscreeninfo(int minor
, struct fb_var_screeninfo
*fbvsp
)
267 if (!initialized
) return ENXIO
;
268 if (minor
!= 0) return ENXIO
;
270 *fbvsp
= omap_fbvs
[minor
];
275 arch_put_varscreeninfo(int minor
, struct fb_var_screeninfo
*fbvsp
)
279 assert(fbvsp
!= NULL
);
281 if (!initialized
) return ENXIO
;
282 if (minor
!= 0) return ENXIO
;
284 /* For now we only allow to play with the yoffset setting */
285 if (fbvsp
->yoffset
!= omap_fbvs
[minor
].yoffset
) {
286 if (/* fbvsp->yoffset < 0 || */ fbvsp
->yoffset
> omap_fbvs
[minor
].yres
) {
290 omap_fbvs
[minor
].yoffset
= fbvsp
->yoffset
;
293 /* Now update hardware with new settings */
294 arch_configure_display(minor
);
299 arch_get_fixscreeninfo(int minor
, struct fb_fix_screeninfo
*fbfsp
)
301 if (!initialized
) return ENXIO
;
302 if (minor
!= 0) return ENXIO
;
304 *fbfsp
= omap_fbfs
[minor
];
309 arch_pan_display(int minor
, struct fb_var_screeninfo
*fbvsp
)
311 return arch_put_varscreeninfo(minor
, fbvsp
);
315 arch_fb_init(int minor
, struct edid_info
*info
)
319 struct minix_mem_range mr
;
321 const struct panel_config
*panel_cfg
= &omap_cfg
[minor
];
323 if (minor
!= 0) return ENXIO
; /* We support only one minor */
327 } else if (info
!= NULL
) {
328 log_debug(&log
, "Configuring Settings based on EDID...\n");
329 r
= configure_with_edid(minor
, info
);
331 log_warn(&log
, "EDID config failed. Using defaults.\n");
332 configure_with_defaults(minor
);
335 log_debug(&log
, "Loading Default Settings...\n");
336 configure_with_defaults(minor
);
341 /* Configure DSS memory access */
342 mr
.mr_base
= OMAP3_DSS_BASE
;
343 mr
.mr_limit
= mr
.mr_base
+ 0x60;
344 if (sys_privctl(SELF
, SYS_PRIV_ADD_MEM
, &mr
) != OK
) {
345 panic("Unable to request access to DSS(1) memory");
348 dss_phys_base
= (vir_bytes
) vm_map_phys(SELF
, (void *) OMAP3_DSS_BASE
,
351 if (dss_phys_base
== (vir_bytes
) MAP_FAILED
) {
352 panic("Unable to request access to DSS(2) memory");
355 /* Configure DISPC memory access */
356 mr
.mr_base
= OMAP3_DISPC_BASE
;
357 mr
.mr_limit
= mr
.mr_base
+ 0x430;
358 if (sys_privctl(SELF
, SYS_PRIV_ADD_MEM
, &mr
) != OK
) {
359 panic("Unable to request access to DISPC(1) memory");
361 dispc_phys_base
= (vir_bytes
) vm_map_phys(SELF
,
362 (void *) OMAP3_DISPC_BASE
,
365 if (dispc_phys_base
== (vir_bytes
) MAP_FAILED
) {
366 panic("Unable to request access to DISPC(2) memory");
369 /* Set timings, screen mode, screen size, etc. */
370 writew(OMAP3_DISPC_TIMINGH(dispc_phys_base
), panel_cfg
->timing_h
);
371 writew(OMAP3_DISPC_TIMINGV(dispc_phys_base
), panel_cfg
->timing_v
);
372 writew(OMAP3_DISPC_POL_FREQ(dispc_phys_base
), panel_cfg
->pol_freq
);
373 writew(OMAP3_DISPC_DIVISOR(dispc_phys_base
), panel_cfg
->divisor
);
374 writew(OMAP3_DISPC_CONFIG(dispc_phys_base
),
375 panel_cfg
->load_mode
<< LOADMODE_SHIFT
);
376 writew(OMAP3_DISPC_CONTROL(dispc_phys_base
),
377 panel_cfg
->panel_type
<< TFTSTN_SHIFT
|
378 panel_cfg
->data_lines
<< DATALINES_SHIFT
);
380 writew((vir_bytes
) OMAP3_DISPC_SIZE_LCD(dispc_phys_base
),
381 panel_cfg
->lcd_size
);
382 writew((vir_bytes
) OMAP3_DISPC_GFX_SIZE(dispc_phys_base
),
383 panel_cfg
->lcd_size
);
384 writew(OMAP3_DISPC_DEFAULT_COLOR0(dispc_phys_base
),
385 panel_cfg
->panel_color
);
387 /* Enable gfx engine */
388 writew(OMAP3_DISPC_GFX_ATTRIBUTES(dispc_phys_base
),
389 (DISPC_GFXBURSTSIZE_16
<< GFXBURSTSIZE_SHIFT
) |
390 (DISPC_GFXFORMAT_RGB24
<< GFXFORMAT_SHIFT
) |
392 writew(OMAP3_DISPC_GFX_ROW_INC(dispc_phys_base
), 1);
393 writew(OMAP3_DISPC_GFX_PIXEL_INC(dispc_phys_base
), 1);
395 /* Allocate contiguous physical memory for the display buffer */
396 fb_size
= omap_fbvs
[minor
].yres_virtual
* omap_fbvs
[minor
].xres_virtual
*
397 (omap_fbvs
[minor
].bits_per_pixel
/ 8);
398 fb_vir
= (vir_bytes
) alloc_contig(fb_size
, 0, &fb_phys
);
399 if (fb_vir
== (vir_bytes
) MAP_FAILED
) {
400 panic("Unable to allocate contiguous memory\n");
403 /* Configure buffer settings and turn on LCD/Digital */
404 arch_configure_display(minor
);