Use EDID when available to configure the frame buffer driver with good settings for the attached display. Change-Id: I69a78155a93e55ffa1ca3ff6621a879a56cdbceb
		
			
				
	
	
		
			189 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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;
 | 
						|
}
 | 
						|
 |