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"
|
||||
|
||||
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}
|
||||
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
|
||||
* have support for EDID (which requires support for i2c, also something we
|
||||
* 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. */
|
||||
/* Architecture dependent part for the framebuffer on the OMAP3.
|
||||
* There's obvious room for improvement.
|
||||
*/
|
||||
|
||||
#include <minix/chardriver.h>
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/fb.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/vm.h>
|
||||
#include <minix/log.h>
|
||||
#include <assert.h>
|
||||
#include <sys/mman.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 "dss.h"
|
||||
#include "fb.h"
|
||||
|
||||
/* default / fallback resolution if EDID reading fails */
|
||||
#define SCREEN_WIDTH 1024
|
||||
#define SCREEN_HEIGHT 600
|
||||
#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 dispc_phys_base; /* Address of dispc phys memory map */
|
||||
static vir_bytes fb_vir;
|
||||
|
@ -50,7 +77,9 @@ static const struct panel_config default_cfg = {
|
|||
.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,
|
||||
.ypanstep = 0,
|
||||
.ywrapstep = 0,
|
||||
|
@ -59,7 +88,9 @@ static const struct fb_fix_screeninfo fbfs = {
|
|||
.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,
|
||||
.yres = SCREEN_HEIGHT,
|
||||
.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
|
||||
readw(vir_bytes addr)
|
||||
{
|
||||
|
@ -101,6 +141,97 @@ writew(vir_bytes addr, u32_t 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
|
||||
arch_configure_display(int minor)
|
||||
{
|
||||
|
@ -110,7 +241,7 @@ arch_configure_display(int minor)
|
|||
if (!initialized) 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),
|
||||
fb_phys + (phys_bytes) off);
|
||||
|
@ -136,7 +267,7 @@ arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
|
|||
if (!initialized) return ENXIO;
|
||||
if (minor != 0) return ENXIO;
|
||||
|
||||
*fbvsp = fbvs;
|
||||
*fbvsp = omap_fbvs[minor];
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -151,12 +282,12 @@ arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
|
|||
if (minor != 0) return ENXIO;
|
||||
|
||||
/* For now we only allow to play with the yoffset setting */
|
||||
if (fbvsp->yoffset != fbvs.yoffset) {
|
||||
if (fbvsp->yoffset < 0 || fbvsp->yoffset > fbvs.yres) {
|
||||
if (fbvsp->yoffset != omap_fbvs[minor].yoffset) {
|
||||
if (fbvsp->yoffset < 0 || fbvsp->yoffset > omap_fbvs[minor].yres) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
fbvs.yoffset = fbvsp->yoffset;
|
||||
omap_fbvs[minor].yoffset = fbvsp->yoffset;
|
||||
}
|
||||
|
||||
/* 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 (minor != 0) return ENXIO;
|
||||
|
||||
*fbfsp = fbfs;
|
||||
*fbfsp = omap_fbfs[minor];
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -181,20 +312,32 @@ arch_pan_display(int minor, struct fb_var_screeninfo *fbvsp)
|
|||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
if (minor != 0) return ENXIO; /* We support only one minor */
|
||||
|
||||
|
||||
if (initialized) {
|
||||
dev->dv_base = fb_vir;
|
||||
dev->dv_size = fb_size;
|
||||
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;
|
||||
|
@ -254,8 +397,8 @@ arch_fb_init(int minor, struct device *dev)
|
|||
writew(OMAP3_DISPC_GFX_PIXEL_INC(dispc_phys_base), 1);
|
||||
|
||||
/* Allocate contiguous physical memory for the display buffer */
|
||||
fb_size = fbvs.yres_virtual * fbvs.xres_virtual *
|
||||
(fbvs.bits_per_pixel / 8);
|
||||
fb_size = omap_fbvs[minor].yres_virtual * omap_fbvs[minor].xres_virtual *
|
||||
(omap_fbvs[minor].bits_per_pixel / 8);
|
||||
fb_vir = (vir_bytes) alloc_contig(fb_size, 0, &fb_phys);
|
||||
if (fb_vir == (vir_bytes) MAP_FAILED) {
|
||||
panic("Unable to allocate contiguous memory\n");
|
||||
|
|
|
@ -11,10 +11,15 @@
|
|||
#include <sys/mman.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 "logos.h"
|
||||
#include "fb_edid.h"
|
||||
#include "fb.h"
|
||||
|
||||
#define FB_DEV_NR 1
|
||||
/*
|
||||
* Function prototypes for the fb driver.
|
||||
*/
|
||||
|
@ -69,11 +74,19 @@ static int open_counter[FB_DEV_NR]; /* Open count */
|
|||
static int
|
||||
fb_open(message *m)
|
||||
{
|
||||
int r;
|
||||
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 (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]++;
|
||||
if (!initialized) {
|
||||
if (has_restarted) {
|
||||
|
@ -363,8 +376,11 @@ sef_cb_init(int type, sef_init_info_t *UNUSED(info))
|
|||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
env_setargs(argc, argv);
|
||||
fb_edid_args_parse();
|
||||
|
||||
sef_local_startup();
|
||||
chardriver_task(&fb_tab, CHARDRIVER_SYNC);
|
||||
return OK;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#ifndef __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_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp);
|
||||
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);
|
||||
|
||||
#define FB_MESSAGE "Hello, world! From framebuffer!\n"
|
||||
#define FB_DEV_NR 1
|
||||
|
||||
#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
|
||||
;
|
||||
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'`
|
||||
case "${BOARD_NAME}" in
|
||||
|
||||
A335BONE)
|
||||
echo "Detected BeagleBone"
|
||||
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 \
|
||||
-label cat24c256.1.50 \
|
||||
-args 'bus=1 address=0x50'
|
||||
|
@ -209,13 +213,35 @@ start)
|
|||
up tps65217 -label tps65217.1.24 \
|
||||
-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)
|
||||
echo "Detected BeagleBone Black"
|
||||
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 \
|
||||
-label cat24c256.1.50 -args 'bus=1 address=0x50'
|
||||
-label cat24c256.1.50 \
|
||||
-args 'bus=1 address=0x50'
|
||||
|
||||
# Start TPS65217 driver for power management.
|
||||
up tps65217 -label tps65217.1.24 \
|
||||
|
@ -224,7 +250,13 @@ start)
|
|||
# Start TDA19988 driver for reading EDID.
|
||||
up tda19988 -label tda19988.1.3470 -args \
|
||||
'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)
|
||||
echo "Unable to detect board -- assuming BeagleBoard-xM"
|
||||
echo -n "Starting i2c device drivers: "
|
||||
|
@ -236,6 +268,22 @@ start)
|
|||
# Set the system time to the time in the TPS65950's RTC
|
||||
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
|
||||
|
||||
|
|
Loading…
Reference in a new issue