fb: auto-configure with EDID
Use EDID when available to configure the frame buffer driver with good settings for the attached display. Change-Id: I69a78155a93e55ffa1ca3ff6621a879a56cdbceb
This commit is contained in:
parent
bdf33c702a
commit
26f14d6b5d
9 changed files with 467 additions and 26 deletions
|
@ -3,7 +3,14 @@ PROG= fb
|
||||||
|
|
||||||
.include "arch/${MACHINE_ARCH}/Makefile.inc"
|
.include "arch/${MACHINE_ARCH}/Makefile.inc"
|
||||||
|
|
||||||
SRCS+= fb.c
|
SRCS+= fb_edid.c fb.c
|
||||||
|
|
||||||
|
# re-use EDID parsing/validation code from NetBSD.
|
||||||
|
.PATH: ${NETBSDSRCDIR}/sys/dev/videomode
|
||||||
|
SRCS+= edid.c pickmode.c videomode.c vesagtf.c
|
||||||
|
|
||||||
|
# Put this dir and the EDID headers (dev/videomode/*.h) in the search path.
|
||||||
|
CPPFLAGS+= -I${.CURDIR} -I${NETBSDSRCDIR}/sys
|
||||||
|
|
||||||
DPADD+= ${LIBCHARDRIVER} ${LIBSYS}
|
DPADD+= ${LIBCHARDRIVER} ${LIBSYS}
|
||||||
LDADD+= -lchardriver -lsys
|
LDADD+= -lchardriver -lsys
|
||||||
|
|
24
drivers/fb/README.txt
Normal file
24
drivers/fb/README.txt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
Frame Buffer Driver
|
||||||
|
===================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
This is the driver for the frame buffer. Currently it only supports the
|
||||||
|
DM37XX (BeagleBoard-xM).
|
||||||
|
|
||||||
|
Testing the Code
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Starting up an instance:
|
||||||
|
|
||||||
|
service up /usr/sbin/fb -dev /dev/fb0 -args edid.0=cat24c256.3.50
|
||||||
|
|
||||||
|
The arguments take the following form:
|
||||||
|
|
||||||
|
edid.X=L where X is the frame buffer device (usually 0) and L is
|
||||||
|
the service label of the service to perform the EDID reading. In
|
||||||
|
the example above, it's the EEPROM with slave address 0x50 on
|
||||||
|
the 3rd I2C bus. If you want to use the defaults and skip EDID
|
||||||
|
reading, you may omit the arguments.
|
||||||
|
|
|
@ -1,23 +1,50 @@
|
||||||
/* Architecture dependent part for the framebuffer on the OMAP3. Since we don't
|
/* Architecture dependent part for the framebuffer on the OMAP3.
|
||||||
* have support for EDID (which requires support for i2c, also something we
|
* There's obvious room for improvement.
|
||||||
* don't have, yet), but we do have a screen with 1024*600 resolution for our
|
*/
|
||||||
* testing purposes, we hardcode that resolution here. There's obvious room for
|
|
||||||
* improvement. */
|
|
||||||
|
|
||||||
#include <minix/chardriver.h>
|
#include <minix/chardriver.h>
|
||||||
#include <minix/drivers.h>
|
#include <minix/drivers.h>
|
||||||
#include <minix/fb.h>
|
#include <minix/fb.h>
|
||||||
#include <minix/type.h>
|
#include <minix/type.h>
|
||||||
#include <minix/vm.h>
|
#include <minix/vm.h>
|
||||||
|
#include <minix/log.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <dev/videomode/videomode.h>
|
||||||
|
#include <dev/videomode/edidvar.h>
|
||||||
|
#include <dev/videomode/edidreg.h>
|
||||||
#include "dss.h"
|
#include "dss.h"
|
||||||
|
#include "fb.h"
|
||||||
|
|
||||||
|
/* default / fallback resolution if EDID reading fails */
|
||||||
#define SCREEN_WIDTH 1024
|
#define SCREEN_WIDTH 1024
|
||||||
#define SCREEN_HEIGHT 600
|
#define SCREEN_HEIGHT 600
|
||||||
#define PAGES_NR 2
|
#define PAGES_NR 2
|
||||||
|
|
||||||
|
#define NSUPPORTED_MODES (4)
|
||||||
|
|
||||||
|
/* List of valid modes from TRM 7.1
|
||||||
|
* Other modes might work (like the default 1024x600), but no guarantees.
|
||||||
|
*/
|
||||||
|
struct supported_modes {
|
||||||
|
int hdisplay;
|
||||||
|
int vdisplay;
|
||||||
|
} omap_supported_modes[NSUPPORTED_MODES] = {
|
||||||
|
{ .hdisplay = 1024, .vdisplay = 768 }, /* XGA */
|
||||||
|
{ .hdisplay = 1280, .vdisplay = 800 }, /* WXGA */
|
||||||
|
{ .hdisplay = 1400, .vdisplay = 1050 }, /* SXGA+ */
|
||||||
|
{ .hdisplay = 1280, .vdisplay = 720 } /* HD 720p */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* local function prototypes */
|
||||||
|
static struct videomode *choose_mode(struct edid_info *info);
|
||||||
|
static void configure_with_defaults(int minor);
|
||||||
|
static int configure_with_edid(int minor, struct edid_info *info);
|
||||||
|
|
||||||
|
/* globals */
|
||||||
static vir_bytes dss_phys_base; /* Address of dss phys memory map */
|
static vir_bytes dss_phys_base; /* Address of dss phys memory map */
|
||||||
static vir_bytes dispc_phys_base; /* Address of dispc phys memory map */
|
static vir_bytes dispc_phys_base; /* Address of dispc phys memory map */
|
||||||
static vir_bytes fb_vir;
|
static vir_bytes fb_vir;
|
||||||
|
@ -50,7 +77,9 @@ static const struct panel_config default_cfg = {
|
||||||
.panel_color = 0xFFFFFF /* WHITE */
|
.panel_color = 0xFFFFFF /* WHITE */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct fb_fix_screeninfo fbfs = {
|
static struct panel_config omap_cfg[FB_DEV_NR];
|
||||||
|
|
||||||
|
static const struct fb_fix_screeninfo default_fbfs = {
|
||||||
.xpanstep = 0,
|
.xpanstep = 0,
|
||||||
.ypanstep = 0,
|
.ypanstep = 0,
|
||||||
.ywrapstep = 0,
|
.ywrapstep = 0,
|
||||||
|
@ -59,7 +88,9 @@ static const struct fb_fix_screeninfo fbfs = {
|
||||||
.mmio_len = 0 /* these are set to 0 */
|
.mmio_len = 0 /* these are set to 0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct fb_var_screeninfo fbvs = {
|
static struct fb_fix_screeninfo omap_fbfs[FB_DEV_NR];
|
||||||
|
|
||||||
|
static const struct fb_var_screeninfo default_fbvs = {
|
||||||
.xres = SCREEN_WIDTH,
|
.xres = SCREEN_WIDTH,
|
||||||
.yres = SCREEN_HEIGHT,
|
.yres = SCREEN_HEIGHT,
|
||||||
.xres_virtual = SCREEN_WIDTH,
|
.xres_virtual = SCREEN_WIDTH,
|
||||||
|
@ -89,6 +120,15 @@ static struct fb_var_screeninfo fbvs = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct fb_var_screeninfo omap_fbvs[FB_DEV_NR];
|
||||||
|
|
||||||
|
/* logging - use with log_warn(), log_info(), log_debug(), log_trace() */
|
||||||
|
static struct log log = {
|
||||||
|
.name = "fb",
|
||||||
|
.log_level = LEVEL_INFO,
|
||||||
|
.log_func = default_log
|
||||||
|
};
|
||||||
|
|
||||||
static inline u32_t
|
static inline u32_t
|
||||||
readw(vir_bytes addr)
|
readw(vir_bytes addr)
|
||||||
{
|
{
|
||||||
|
@ -101,6 +141,97 @@ writew(vir_bytes addr, u32_t val)
|
||||||
*((volatile u32_t *) addr) = val;
|
*((volatile u32_t *) addr) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct videomode *
|
||||||
|
choose_mode(struct edid_info *info)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* choose the highest resolution supported by both the SoC and screen */
|
||||||
|
for (i = info->edid_nmodes - 1; i >= 0; i--) {
|
||||||
|
for (j = NSUPPORTED_MODES - 1; j >= 0; j--) {
|
||||||
|
|
||||||
|
if (info->edid_modes[i].hdisplay ==
|
||||||
|
omap_supported_modes[j].hdisplay &&
|
||||||
|
info->edid_modes[i].vdisplay ==
|
||||||
|
omap_supported_modes[j].vdisplay) {
|
||||||
|
|
||||||
|
return &(info->edid_modes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
configure_with_edid(int minor, struct edid_info *info)
|
||||||
|
{
|
||||||
|
struct videomode *mode;
|
||||||
|
|
||||||
|
if (info == NULL || minor < 0 || minor >= FB_DEV_NR) {
|
||||||
|
log_warn(&log, "Invalid minor #%d or info == NULL\n", minor);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If debugging or tracing, print the contents of info */
|
||||||
|
if (log.log_level >= LEVEL_DEBUG) {
|
||||||
|
log_debug(&log, "--- EDID - START ---\n");
|
||||||
|
edid_print(info);
|
||||||
|
log_debug(&log, "--- EDID - END ---\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Choose the preferred mode. */
|
||||||
|
mode = choose_mode(info);
|
||||||
|
if (mode == NULL) {
|
||||||
|
log_warn(&log, "Couldn't find a supported resolution.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* apply the default settings since we don't overwrite every field
|
||||||
|
*/
|
||||||
|
configure_with_defaults(minor);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* apply the settings corresponding to the given EDID
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* panel_config */
|
||||||
|
omap_cfg[minor].lcd_size = ((mode->vdisplay - 1) << 16 | (mode->hdisplay - 1));
|
||||||
|
|
||||||
|
if (EDID_FEATURES_DISP_TYPE(info->edid_features) ==
|
||||||
|
EDID_FEATURES_DISP_TYPE_MONO) {
|
||||||
|
omap_cfg[minor].panel_type = 0x00; /* Mono */
|
||||||
|
} else {
|
||||||
|
omap_cfg[minor].panel_type = 0x01; /* RGB/Color */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fb_fix_screeninfo */
|
||||||
|
omap_fbfs[minor].line_length = mode->hdisplay * 4;
|
||||||
|
|
||||||
|
/* fb_var_screeninfo */
|
||||||
|
omap_fbvs[minor].xres = mode->hdisplay;
|
||||||
|
omap_fbvs[minor].yres = mode->vdisplay;
|
||||||
|
omap_fbvs[minor].xres_virtual = mode->hdisplay;
|
||||||
|
omap_fbvs[minor].yres_virtual = mode->vdisplay*2;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
configure_with_defaults(int minor)
|
||||||
|
{
|
||||||
|
if (minor < 0 || minor >= FB_DEV_NR) {
|
||||||
|
log_warn(&log, "Invalid minor #%d\n", minor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy the default values into this minor's configuration */
|
||||||
|
memcpy(&omap_cfg[minor], &default_cfg, sizeof(struct panel_config));
|
||||||
|
memcpy(&omap_fbfs[minor], &default_fbfs, sizeof(struct fb_fix_screeninfo));
|
||||||
|
memcpy(&omap_fbvs[minor], &default_fbvs, sizeof(struct fb_var_screeninfo));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arch_configure_display(int minor)
|
arch_configure_display(int minor)
|
||||||
{
|
{
|
||||||
|
@ -110,7 +241,7 @@ arch_configure_display(int minor)
|
||||||
if (!initialized) return;
|
if (!initialized) return;
|
||||||
if (minor != 0) return;
|
if (minor != 0) return;
|
||||||
|
|
||||||
off = fbvs.yoffset * fbvs.xres_virtual * (fbvs.bits_per_pixel/8);
|
off = omap_fbvs[minor].yoffset * omap_fbvs[minor].xres_virtual * (omap_fbvs[minor].bits_per_pixel/8);
|
||||||
|
|
||||||
writew((vir_bytes) OMAP3_DISPC_GFX_BA0(dispc_phys_base),
|
writew((vir_bytes) OMAP3_DISPC_GFX_BA0(dispc_phys_base),
|
||||||
fb_phys + (phys_bytes) off);
|
fb_phys + (phys_bytes) off);
|
||||||
|
@ -136,7 +267,7 @@ arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
|
||||||
if (!initialized) return ENXIO;
|
if (!initialized) return ENXIO;
|
||||||
if (minor != 0) return ENXIO;
|
if (minor != 0) return ENXIO;
|
||||||
|
|
||||||
*fbvsp = fbvs;
|
*fbvsp = omap_fbvs[minor];
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,12 +282,12 @@ arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
|
||||||
if (minor != 0) return ENXIO;
|
if (minor != 0) return ENXIO;
|
||||||
|
|
||||||
/* For now we only allow to play with the yoffset setting */
|
/* For now we only allow to play with the yoffset setting */
|
||||||
if (fbvsp->yoffset != fbvs.yoffset) {
|
if (fbvsp->yoffset != omap_fbvs[minor].yoffset) {
|
||||||
if (fbvsp->yoffset < 0 || fbvsp->yoffset > fbvs.yres) {
|
if (fbvsp->yoffset < 0 || fbvsp->yoffset > omap_fbvs[minor].yres) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fbvs.yoffset = fbvsp->yoffset;
|
omap_fbvs[minor].yoffset = fbvsp->yoffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now update hardware with new settings */
|
/* Now update hardware with new settings */
|
||||||
|
@ -170,7 +301,7 @@ arch_get_fixscreeninfo(int minor, struct fb_fix_screeninfo *fbfsp)
|
||||||
if (!initialized) return ENXIO;
|
if (!initialized) return ENXIO;
|
||||||
if (minor != 0) return ENXIO;
|
if (minor != 0) return ENXIO;
|
||||||
|
|
||||||
*fbfsp = fbfs;
|
*fbfsp = omap_fbfs[minor];
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,20 +312,32 @@ arch_pan_display(int minor, struct fb_var_screeninfo *fbvsp)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
arch_fb_init(int minor, struct device *dev)
|
arch_fb_init(int minor, struct device *dev, struct edid_info *info)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
u32_t rdispc;
|
u32_t rdispc;
|
||||||
struct minix_mem_range mr;
|
struct minix_mem_range mr;
|
||||||
|
|
||||||
const struct panel_config *panel_cfg = &default_cfg;
|
const struct panel_config *panel_cfg = &omap_cfg[minor];
|
||||||
|
|
||||||
assert(dev != NULL);
|
assert(dev != NULL);
|
||||||
if (minor != 0) return ENXIO; /* We support only one minor */
|
if (minor != 0) return ENXIO; /* We support only one minor */
|
||||||
|
|
||||||
|
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
dev->dv_base = fb_vir;
|
dev->dv_base = fb_vir;
|
||||||
dev->dv_size = fb_size;
|
dev->dv_size = fb_size;
|
||||||
return OK;
|
return OK;
|
||||||
|
} else if (info != NULL) {
|
||||||
|
log_debug(&log, "Configuring Settings based on EDID...\n");
|
||||||
|
r = configure_with_edid(minor, info);
|
||||||
|
if (r != OK) {
|
||||||
|
log_warn(&log, "EDID config failed. Using defaults.\n");
|
||||||
|
configure_with_defaults(minor);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log_debug(&log, "Loading Default Settings...\n");
|
||||||
|
configure_with_defaults(minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
|
@ -254,8 +397,8 @@ arch_fb_init(int minor, struct device *dev)
|
||||||
writew(OMAP3_DISPC_GFX_PIXEL_INC(dispc_phys_base), 1);
|
writew(OMAP3_DISPC_GFX_PIXEL_INC(dispc_phys_base), 1);
|
||||||
|
|
||||||
/* Allocate contiguous physical memory for the display buffer */
|
/* Allocate contiguous physical memory for the display buffer */
|
||||||
fb_size = fbvs.yres_virtual * fbvs.xres_virtual *
|
fb_size = omap_fbvs[minor].yres_virtual * omap_fbvs[minor].xres_virtual *
|
||||||
(fbvs.bits_per_pixel / 8);
|
(omap_fbvs[minor].bits_per_pixel / 8);
|
||||||
fb_vir = (vir_bytes) alloc_contig(fb_size, 0, &fb_phys);
|
fb_vir = (vir_bytes) alloc_contig(fb_size, 0, &fb_phys);
|
||||||
if (fb_vir == (vir_bytes) MAP_FAILED) {
|
if (fb_vir == (vir_bytes) MAP_FAILED) {
|
||||||
panic("Unable to allocate contiguous memory\n");
|
panic("Unable to allocate contiguous memory\n");
|
||||||
|
|
|
@ -11,10 +11,15 @@
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <dev/videomode/videomode.h>
|
||||||
|
#include <dev/videomode/edidvar.h>
|
||||||
|
#include <dev/videomode/edidreg.h>
|
||||||
|
|
||||||
#include "logos.h"
|
#include "logos.h"
|
||||||
|
#include "fb_edid.h"
|
||||||
#include "fb.h"
|
#include "fb.h"
|
||||||
|
|
||||||
#define FB_DEV_NR 1
|
|
||||||
/*
|
/*
|
||||||
* Function prototypes for the fb driver.
|
* Function prototypes for the fb driver.
|
||||||
*/
|
*/
|
||||||
|
@ -69,11 +74,19 @@ static int open_counter[FB_DEV_NR]; /* Open count */
|
||||||
static int
|
static int
|
||||||
fb_open(message *m)
|
fb_open(message *m)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
static int initialized = 0;
|
static int initialized = 0;
|
||||||
|
static struct edid_info info;
|
||||||
|
static struct edid_info *infop = NULL;
|
||||||
|
|
||||||
if (m->DEVICE < 0 || m->DEVICE >= FB_DEV_NR) return ENXIO;
|
if (m->DEVICE < 0 || m->DEVICE >= FB_DEV_NR) return ENXIO;
|
||||||
|
|
||||||
if (arch_fb_init(m->DEVICE, &fb_device[m->DEVICE]) == OK) {
|
if (!initialized) {
|
||||||
|
r = fb_edid_read(m->DEVICE, &info);
|
||||||
|
infop = (r == 0) ? &info : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arch_fb_init(m->DEVICE, &fb_device[m->DEVICE], infop) == OK) {
|
||||||
open_counter[m->DEVICE]++;
|
open_counter[m->DEVICE]++;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
if (has_restarted) {
|
if (has_restarted) {
|
||||||
|
@ -363,8 +376,11 @@ sef_cb_init(int type, sef_init_info_t *UNUSED(info))
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(void)
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
env_setargs(argc, argv);
|
||||||
|
fb_edid_args_parse();
|
||||||
|
|
||||||
sef_local_startup();
|
sef_local_startup();
|
||||||
chardriver_task(&fb_tab, CHARDRIVER_SYNC);
|
chardriver_task(&fb_tab, CHARDRIVER_SYNC);
|
||||||
return OK;
|
return OK;
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#ifndef __FB_H__
|
#ifndef __FB_H__
|
||||||
#define __FB_H__
|
#define __FB_H__
|
||||||
|
|
||||||
int arch_fb_init(int minor, struct device *dev);
|
#include <minix/fb.h>
|
||||||
|
|
||||||
|
int arch_fb_init(int minor, struct device *dev, struct edid_info *info);
|
||||||
int arch_get_device(int minor, struct device *dev);
|
int arch_get_device(int minor, struct device *dev);
|
||||||
int arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp);
|
int arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp);
|
||||||
int arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvs_copy);
|
int arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvs_copy);
|
||||||
|
@ -9,5 +11,6 @@ int arch_get_fixscreeninfo(int minor, struct fb_fix_screeninfo *fbfsp);
|
||||||
int arch_pan_display(int minor, struct fb_var_screeninfo *fbvs_copy);
|
int arch_pan_display(int minor, struct fb_var_screeninfo *fbvs_copy);
|
||||||
|
|
||||||
#define FB_MESSAGE "Hello, world! From framebuffer!\n"
|
#define FB_MESSAGE "Hello, world! From framebuffer!\n"
|
||||||
|
#define FB_DEV_NR 1
|
||||||
|
|
||||||
#endif /* __FB_H__ */
|
#endif /* __FB_H__ */
|
||||||
|
|
188
drivers/fb/fb_edid.c
Normal file
188
drivers/fb/fb_edid.c
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* Handle reading the EDID information, validating it, and parsing it into
|
||||||
|
* a struct edid_info. EDID reads are done using the Block Device Protocol
|
||||||
|
* as it's already supported by the cat24c256 driver and there is no need
|
||||||
|
* to add yet another message format/type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <minix/fb.h>
|
||||||
|
#include <minix/chardriver.h>
|
||||||
|
#include <minix/drivers.h>
|
||||||
|
#include <minix/ds.h>
|
||||||
|
#include <minix/rs.h>
|
||||||
|
#include <minix/log.h>
|
||||||
|
#include <minix/sysutil.h>
|
||||||
|
#include <minix/type.h>
|
||||||
|
#include <minix/vm.h>
|
||||||
|
#include <sys/ioc_fb.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <dev/videomode/videomode.h>
|
||||||
|
#include <dev/videomode/edidvar.h>
|
||||||
|
#include <dev/videomode/edidreg.h>
|
||||||
|
|
||||||
|
#include "fb_edid.h"
|
||||||
|
#include "fb.h"
|
||||||
|
|
||||||
|
static int do_read(endpoint_t endpt, uint8_t *buf, size_t bufsize);
|
||||||
|
|
||||||
|
/* logging - use with log_warn(), log_info(), log_debug(), log_trace() */
|
||||||
|
static struct log log = {
|
||||||
|
.name = "edid",
|
||||||
|
.log_level = LEVEL_INFO,
|
||||||
|
.log_func = default_log
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Labels corresponding to drivers which provide EDID.
|
||||||
|
*/
|
||||||
|
static char edid_providers[FB_DEV_NR][RS_MAX_LABEL_LEN+1];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Populate edid_providers from command line arguments. The service command
|
||||||
|
* should get EDID providers like this: "-args edid.0=tda19988.1.3470" where
|
||||||
|
* 0 is the minor number of the frame buffer, tda19988 is the device driver,
|
||||||
|
* 1 is the i2c bus and 3470 is the slave address (the TDA19988 has 2 slave
|
||||||
|
* addresses 0x34 and 0x70).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fb_edid_args_parse(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int r;
|
||||||
|
char key[32];
|
||||||
|
|
||||||
|
for (i = 0; i < FB_DEV_NR; i++) {
|
||||||
|
|
||||||
|
memset(key, '\0', 32);
|
||||||
|
snprintf(key, 32, "edid.%d", i);
|
||||||
|
|
||||||
|
memset(edid_providers[i], '\0', RS_MAX_LABEL_LEN);
|
||||||
|
r = env_get_param(key, edid_providers[i], RS_MAX_LABEL_LEN);
|
||||||
|
if (r == OK) {
|
||||||
|
log_debug(&log, "Found key:%s value:%s\n", key, edid_providers[i]);
|
||||||
|
} else {
|
||||||
|
/* not an error, user is allowed to omit EDID
|
||||||
|
* providers in order to skip EDID reading and use
|
||||||
|
* the default settings.
|
||||||
|
*/
|
||||||
|
log_debug(&log, "Couldn't find key:%s\n", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a read request to the block driver at endpoint endpt.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
do_read(endpoint_t driver_endpt, uint8_t *buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
message m;
|
||||||
|
cp_grant_id_t grant_nr;
|
||||||
|
|
||||||
|
/* Open Device - required for drivers using libblockdriver */
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
m.m_type = BDEV_OPEN;
|
||||||
|
m.BDEV_ACCESS = R_BIT;
|
||||||
|
m.BDEV_ID = 0;
|
||||||
|
m.BDEV_MINOR = 0;
|
||||||
|
|
||||||
|
r = sendrec(driver_endpt, &m);
|
||||||
|
if (r != OK) {
|
||||||
|
log_debug(&log, "sendrec(BDEV_OPEN) failed (r=%d)\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
grant_nr = cpf_grant_direct(driver_endpt, (vir_bytes) buf,
|
||||||
|
bufsize, CPF_READ | CPF_WRITE);
|
||||||
|
|
||||||
|
/* Perform the read */
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
m.m_type = BDEV_READ;
|
||||||
|
m.BDEV_MINOR = 0;
|
||||||
|
m.BDEV_COUNT = bufsize;
|
||||||
|
m.BDEV_GRANT = grant_nr;
|
||||||
|
m.BDEV_FLAGS = BDEV_NOPAGE; /* the EEPROMs used for EDID are pageless */
|
||||||
|
m.BDEV_ID = 0;
|
||||||
|
m.BDEV_POS_LO = 0;
|
||||||
|
m.BDEV_POS_HI = 0;
|
||||||
|
|
||||||
|
r = sendrec(driver_endpt, &m);
|
||||||
|
cpf_revoke(grant_nr);
|
||||||
|
if (r != OK) {
|
||||||
|
log_debug(&log, "sendrec(BDEV_READ) failed (r=%d)\n", r);
|
||||||
|
/* Clean-up: try to close the device */
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
m.m_type = BDEV_CLOSE;
|
||||||
|
m.BDEV_MINOR = 0;
|
||||||
|
m.BDEV_ID = 0;
|
||||||
|
sendrec(driver_endpt, &m);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the device */
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
m.m_type = BDEV_CLOSE;
|
||||||
|
m.BDEV_MINOR = 0;
|
||||||
|
m.BDEV_ID = 0;
|
||||||
|
r = sendrec(driver_endpt, &m);
|
||||||
|
if (r != OK) {
|
||||||
|
log_debug(&log, "sendrec(BDEV_CLOSE) failed (r=%d)\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fb_edid_read(int minor, struct edid_info *info)
|
||||||
|
{
|
||||||
|
|
||||||
|
int r;
|
||||||
|
uint8_t buffer[128];
|
||||||
|
endpoint_t endpt;
|
||||||
|
|
||||||
|
if (info == NULL || minor < 0 || minor >= FB_DEV_NR ||
|
||||||
|
edid_providers[minor][0] == '\0') {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug(&log, "Contacting %s to get EDID.\n", edid_providers[minor]);
|
||||||
|
|
||||||
|
/* Look up the endpoint that corresponds to the label */
|
||||||
|
endpt = 0;
|
||||||
|
r = ds_retrieve_label_endpt(edid_providers[minor], &endpt);
|
||||||
|
if (r != 0 || endpt == 0) {
|
||||||
|
log_warn(&log, "Couldn't find endpoint for label '%s'\n", edid_providers[minor]);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the request and put the resulting EDID into the buffer. */
|
||||||
|
memset(buffer, 0x00, 128);
|
||||||
|
r = do_read(endpt, buffer, 128);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug(&log, "Failed to read EDID\n");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse and validate EDID */
|
||||||
|
r = edid_parse(buffer, info);
|
||||||
|
if (r != 0) {
|
||||||
|
log_warn(&log, "Invalid EDID data in buffer.\n");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug(&log, "EDID Retrieved and Parsed OK\n");
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
12
drivers/fb/fb_edid.h
Normal file
12
drivers/fb/fb_edid.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef __EDID_H
|
||||||
|
#define __EDID_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <dev/videomode/videomode.h>
|
||||||
|
#include <dev/videomode/edidvar.h>
|
||||||
|
#include <dev/videomode/edidreg.h>
|
||||||
|
|
||||||
|
int fb_edid_args_parse(void);
|
||||||
|
int fb_edid_read(int minor, struct edid_info *info);
|
||||||
|
|
||||||
|
#endif /* __EDID_H */
|
|
@ -573,7 +573,7 @@ service fb
|
||||||
PRIVCTL # 4
|
PRIVCTL # 4
|
||||||
;
|
;
|
||||||
ipc
|
ipc
|
||||||
SYSTEM pm rs ds vm vfs tda19988
|
SYSTEM pm rs ds vm vfs cat24c256 tda19988
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
54
etc/usr/rc
54
etc/usr/rc
|
@ -197,10 +197,14 @@ start)
|
||||||
|
|
||||||
BOARD_NAME=`eepromread -i | sed -n 's/^BOARD_NAME : \(.*\)$/\1/p'`
|
BOARD_NAME=`eepromread -i | sed -n 's/^BOARD_NAME : \(.*\)$/\1/p'`
|
||||||
case "${BOARD_NAME}" in
|
case "${BOARD_NAME}" in
|
||||||
|
|
||||||
A335BONE)
|
A335BONE)
|
||||||
echo "Detected BeagleBone"
|
echo "Detected BeagleBone"
|
||||||
echo -n "Starting i2c device drivers: "
|
echo -n "Starting i2c device drivers: "
|
||||||
test -e /dev/eepromb1s50 || (cd /dev && MAKEDEV eepromb1s50)
|
|
||||||
|
# start EEPROM driver for reading board info
|
||||||
|
test -e /dev/eepromb1s50 || \
|
||||||
|
(cd /dev && MAKEDEV eepromb1s50)
|
||||||
up cat24c256 -dev /dev/eepromb1s50 \
|
up cat24c256 -dev /dev/eepromb1s50 \
|
||||||
-label cat24c256.1.50 \
|
-label cat24c256.1.50 \
|
||||||
-args 'bus=1 address=0x50'
|
-args 'bus=1 address=0x50'
|
||||||
|
@ -209,13 +213,35 @@ start)
|
||||||
up tps65217 -label tps65217.1.24 \
|
up tps65217 -label tps65217.1.24 \
|
||||||
-args 'bus=1 address=0x24'
|
-args 'bus=1 address=0x24'
|
||||||
|
|
||||||
|
# check for the presence of a display
|
||||||
|
eepromread -f /dev/i2c-2 -n > /dev/null 2>&1
|
||||||
|
RESULT=$?
|
||||||
|
if [ $RESULT -eq 0 ]
|
||||||
|
then
|
||||||
|
# start eeprom driver for reading EDID.
|
||||||
|
test -e /dev/eepromb2s50 || \
|
||||||
|
(cd /dev && MAKEDEV eepromb2s50)
|
||||||
|
up cat24c256 -dev /dev/eepromb2s50 \
|
||||||
|
-label cat24c256.2.50 \
|
||||||
|
-args 'bus=2 address=0x50'
|
||||||
|
|
||||||
|
# start frame buffer
|
||||||
|
#up fb -dev /dev/fb0 -args edid.0=cat24c256.2.50
|
||||||
|
# fb hasn't been ported to AM335X yet.
|
||||||
|
fi
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
A335BNLT)
|
A335BNLT)
|
||||||
echo "Detected BeagleBone Black"
|
echo "Detected BeagleBone Black"
|
||||||
echo -n "Starting i2c device drivers: "
|
echo -n "Starting i2c device drivers: "
|
||||||
test -e /dev/eepromb1s50 || (cd /dev && MAKEDEV eepromb1s50)
|
|
||||||
|
# start EEPROM driver for reading board info
|
||||||
|
test -e /dev/eepromb1s50 || \
|
||||||
|
(cd /dev && MAKEDEV eepromb1s50)
|
||||||
up cat24c256 -dev /dev/eepromb1s50 \
|
up cat24c256 -dev /dev/eepromb1s50 \
|
||||||
-label cat24c256.1.50 -args 'bus=1 address=0x50'
|
-label cat24c256.1.50 \
|
||||||
|
-args 'bus=1 address=0x50'
|
||||||
|
|
||||||
# Start TPS65217 driver for power management.
|
# Start TPS65217 driver for power management.
|
||||||
up tps65217 -label tps65217.1.24 \
|
up tps65217 -label tps65217.1.24 \
|
||||||
|
@ -224,7 +250,13 @@ start)
|
||||||
# Start TDA19988 driver for reading EDID.
|
# Start TDA19988 driver for reading EDID.
|
||||||
up tda19988 -label tda19988.1.3470 -args \
|
up tda19988 -label tda19988.1.3470 -args \
|
||||||
'cec_bus=1 cec_address=0x34 hdmi_bus=1 hdmi_address=0x70'
|
'cec_bus=1 cec_address=0x34 hdmi_bus=1 hdmi_address=0x70'
|
||||||
|
|
||||||
|
# start frame buffer
|
||||||
|
#up fb -dev /dev/fb0 -args edid.0=tda19988.1.3470
|
||||||
|
# fb hasn't been ported to AM335X yet.
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
UNKNOWN)
|
UNKNOWN)
|
||||||
echo "Unable to detect board -- assuming BeagleBoard-xM"
|
echo "Unable to detect board -- assuming BeagleBoard-xM"
|
||||||
echo -n "Starting i2c device drivers: "
|
echo -n "Starting i2c device drivers: "
|
||||||
|
@ -236,6 +268,22 @@ start)
|
||||||
# Set the system time to the time in the TPS65950's RTC
|
# Set the system time to the time in the TPS65950's RTC
|
||||||
readclock
|
readclock
|
||||||
|
|
||||||
|
# check for the presence of a display
|
||||||
|
eepromread -f /dev/i2c-3 -n > /dev/null 2>&1
|
||||||
|
RESULT=$?
|
||||||
|
if [ $RESULT -eq 0 ]
|
||||||
|
then
|
||||||
|
# start eeprom driver for reading edid
|
||||||
|
test -e /dev/eepromb3s50 || \
|
||||||
|
(cd /dev && MAKEDEV eepromb3s50)
|
||||||
|
up cat24c256 -dev /dev/eepromb3s50 \
|
||||||
|
-label cat24c256.3.50 \
|
||||||
|
-args 'bus=3 address=0x50'
|
||||||
|
|
||||||
|
# start frame buffer
|
||||||
|
up fb -dev /dev/fb0 -args edid.0=cat24c256.3.50
|
||||||
|
fi
|
||||||
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue