blob: 1a8702db0b014219ffbc712912d9eb1be06325b8 [file] [log] [blame]
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <errno.h>
#include "ch7036.h"
/* Fast load of firmware does not work yet */
/* #define FASTLOAD */
int ch7036_debugi2c = 0;
int ch7036_cur_page = -1;
static int ch_page_map[5] = {-1, 0, 1, 3, 4};
static int ch_page_revmap[8] = {1, 2, -1, 3, 4, -1, -1, -1};
/* Firmware data area moved in firmware 1.2 */
#ifdef FIRMWARE_0_86
#define MCU_DATA_PAGE 0x04
static unsigned char es_map[16] = {
0x08,0x09,0x0F,0x10,0x11,0x12,0x13,0x14,
0x15,0x16,0x17,0x28,0x29,0x47,0x48,0x49
}; //for A version 8/15/10 DT
#else
#define MCU_DATA_PAGE 0x01
static unsigned char es_map[16] = {
0x26,0x27,0x42,0x43,0x44,0x45,0x46,0x47,
0x6A,0x51,0x52,0x53,0x57,0x58,0x59,0x5A
};//for D version 8/15/10 DT
#endif
static unsigned char changed[5][256];
typedef struct {
unsigned char size; // total size should be less than 16 bytes
unsigned char ver_major;
unsigned char ver_minor;
unsigned char did;
// CH7036 device id
unsigned char rid;
// CH7036 revision id
unsigned char capbility; // FW capability;
// 0x01: EDID_Reading
unsigned char reserved;
} FW7036_CFG;
static uint8 g_DefRegMap[5][0x80] = {
//Page 0 :
{
0x56, // Index = 0x00 ( page 0 )
0xF0, // Index = 0x01 ( page 0 )
0xF3, // Index = 0x02 ( page 0 )
0x00, // Index = 0x03 ( page 0 )
0x36, // Index = 0x04 ( page 0 )
0x58, // Index = 0x05 ( page 0 )
0xAC, // Index = 0x06 ( page 0 )
0xDD, // Index = 0x07 ( page 0 )
0x0F, // Index = 0x08 ( page 0 )
0x1F, // Index = 0x09 ( page 0 )
0xB4, // Index = 0x0A ( page 0 )
0x1A, // Index = 0x0B ( page 0 )
0x80, // Index = 0x0C ( page 0 )
0x20, // Index = 0x0D ( page 0 )
0x00, // Index = 0x0E ( page 0 )
0x10, // Index = 0x0F ( page 0 )
0x60, // Index = 0x10 ( page 0 )
0x11, // Index = 0x11 ( page 0 )
0xE0, // Index = 0x12 ( page 0 )
0x0D, // Index = 0x13 ( page 0 )
0x00, // Index = 0x14 ( page 0 )
0x0A, // Index = 0x15 ( page 0 )
0x02, // Index = 0x16 ( page 0 )
0x00, // Index = 0x17 ( page 0 )
0x00, // Index = 0x18 ( page 0 )
0xF8, // Index = 0x19 ( page 0 )
0x00, // Index = 0x1A ( page 0 )
0x00, // Index = 0x1B ( page 0 )
0x00, // Index = 0x1C ( page 0 )
0x00, // Index = 0x1D ( page 0 )
0x00, // Index = 0x1E ( page 0 )
0x1A, // Index = 0x1F ( page 0 )
0x80, // Index = 0x20 ( page 0 )
0x20, // Index = 0x21 ( page 0 )
0x00, // Index = 0x22 ( page 0 )
0x10, // Index = 0x23 ( page 0 )
0x60, // Index = 0x24 ( page 0 )
0x11, // Index = 0x25 ( page 0 )
0xE0, // Index = 0x26 ( page 0 )
0x0D, // Index = 0x27 ( page 0 )
0x00, // Index = 0x28 ( page 0 )
0x0A, // Index = 0x29 ( page 0 )
0x02, // Index = 0x2A ( page 0 )
0x08, // Index = 0x2B ( page 0 )
0x00, // Index = 0x2C ( page 0 )
0x00, // Index = 0x2D ( page 0 )
0x3C, // Index = 0x2E ( page 0 )
0x00, // Index = 0x2F ( page 0 )
0x01, // Index = 0x30 ( page 0 )
0x01, // Index = 0x31 ( page 0 )
0xC0, // Index = 0x32 ( page 0 )
0x01, // Index = 0x33 ( page 0 )
0x01, // Index = 0x34 ( page 0 )
0x80, // Index = 0x35 ( page 0 )
0x40, // Index = 0x36 ( page 0 )
0x40, // Index = 0x37 ( page 0 )
0x47, // Index = 0x38 ( page 0 )
0x88, // Index = 0x39 ( page 0 )
0x00, // Index = 0x3A ( page 0 )
0x00, // Index = 0x3B ( page 0 )
0x00, // Index = 0x3C ( page 0 )
0x86, // Index = 0x3D ( page 0 )
0x00, // Index = 0x3E ( page 0 )
0x11, // Index = 0x3F ( page 0 )
0x0E, // Index = 0x40 ( page 0 )
0x00, // Index = 0x41 ( page 0 )
0x00, // Index = 0x42 ( page 0 )
0x00, // Index = 0x43 ( page 0 )
0x00, // Index = 0x44 ( page 0 )
0x00, // Index = 0x45 ( page 0 )
0x00, // Index = 0x46 ( page 0 )
0x00, // Index = 0x47 ( page 0 )
0x00, // Index = 0x48 ( page 0 )
0x00, // Index = 0x49 ( page 0 )
0x00, // Index = 0x4A ( page 0 )
0x40, // Index = 0x4B ( page 0 )
0x40, // Index = 0x4C ( page 0 )
0x80, // Index = 0x4D ( page 0 )
0x00, // Index = 0x4E ( page 0 )
0x00, // Index = 0x4F ( page 0 )
0x00, // Index = 0x50 ( page 0 )
0x1F, // Index = 0x51 ( page 0 )
0xFF, // Index = 0x52 ( page 0 )
0x00, // Index = 0x53 ( page 0 )
0x80, // Index = 0x54 ( page 0 )
0x10, // Index = 0x55 ( page 0 )
0x60, // Index = 0x56 ( page 0 )
0x00, // Index = 0x57 ( page 0 )
0x0A, // Index = 0x58 ( page 0 )
0x02, // Index = 0x59 ( page 0 )
0x08, // Index = 0x5A ( page 0 )
0x00, // Index = 0x5B ( page 0 )
0x00, // Index = 0x5C ( page 0 )
0x00, // Index = 0x5D ( page 0 )
0x40, // Index = 0x5E ( page 0 )
0x00, // Index = 0x5F ( page 0 )
0x00, // Index = 0x60 ( page 0 )
0x00, // Index = 0x61 ( page 0 )
0x00, // Index = 0x62 ( page 0 )
0x01, // Index = 0x63 ( page 0 )
0x2D, // Index = 0x64 ( page 0 )
0x90, // Index = 0x65 ( page 0 )
0x20, // Index = 0x66 ( page 0 )
0x22, // Index = 0x67 ( page 0 )
0x44, // Index = 0x68 ( page 0 )
0x24, // Index = 0x69 ( page 0 )
0x40, // Index = 0x6A ( page 0 )
0x00, // Index = 0x6B ( page 0 )
0x10, // Index = 0x6C ( page 0 )
0x00, // Index = 0x6D ( page 0 )
0xA0, // Index = 0x6E ( page 0 )
0x4B, // Index = 0x6F ( page 0 )
0x18, // Index = 0x70 ( page 0 )
0x01, // Index = 0x71 ( page 0 )
0x00, // Index = 0x72 ( page 0 )
0x00, // Index = 0x73 ( page 0 )
0x20, // Index = 0x74 ( page 0 )
0x80, // Index = 0x75 ( page 0 )
0x18, // Index = 0x76 ( page 0 )
0x00, // Index = 0x77 ( page 0 )
0x00, // Index = 0x78 ( page 0 )
0x01, // Index = 0x79 ( page 0 )
0x00, // Index = 0x7A ( page 0 )
0x00, // Index = 0x7B ( page 0 )
0x00, // Index = 0x7C ( page 0 )
0xFF, // Index = 0x7D ( page 0 )
0x0F, // Index = 0x7E ( page 0 )
0x00, // Index = 0x7F ( page 0 )
},
//Page 1:
{
0x56, // Index = 0x00 ( page 1 )
0xF0, // Index = 0x01 ( page 1 )
0xF3, // Index = 0x02 ( page 1 )
0x01, // Index = 0x03 ( page 1 )
0x36, // Index = 0x04 ( page 1 )
0x58, // Index = 0x05 ( page 1 )
0xAC, // Index = 0x06 ( page 1 )
0x20, // Index = 0x07 ( page 1 )
0x00, // Index = 0x08 ( page 1 )
0x4B, // Index = 0x09 ( page 1 )
0x00, // Index = 0x0A ( page 1 )
0x6D, // Index = 0x0B ( page 1 )
0x6A, // Index = 0x0C ( page 1 )
0x51, // Index = 0x0D ( page 1 )
0x93, // Index = 0x0E ( page 1 )
0x1C, // Index = 0x0F ( page 1 )
0x00, // Index = 0x10 ( page 1 )
0x08, // Index = 0x11 ( page 1 )
0xC5, // Index = 0x12 ( page 1 )
0xA8, // Index = 0x13 ( page 1 )
0x91, // Index = 0x14 ( page 1 )
0x68, // Index = 0x15 ( page 1 )
0x29, // Index = 0x16 ( page 1 )
0x0E, // Index = 0x17 ( page 1 )
0xC8, // Index = 0x18 ( page 1 )
0x42, // Index = 0x19 ( page 1 )
0x6C, // Index = 0x1A ( page 1 )
0x00, // Index = 0x1B ( page 1 )
0x00, // Index = 0x1C ( page 1 )
0x00, // Index = 0x1D ( page 1 )
0x00, // Index = 0x1E ( page 1 )
0x00, // Index = 0x1F ( page 1 )
0x00, // Index = 0x20 ( page 1 )
0x10, // Index = 0x21 ( page 1 )
0x07, // Index = 0x22 ( page 1 )
0xFF, // Index = 0x23 ( page 1 )
0xB6, // Index = 0x24 ( page 1 )
0x10, // Index = 0x25 ( page 1 )
0x00, // Index = 0x26 ( page 1 )
0x00, // Index = 0x27 ( page 1 )
0x15, // Index = 0x28 ( page 1 )
0x18, // Index = 0x29 ( page 1 )
0x00, // Index = 0x2A ( page 1 )
0x00, // Index = 0x2B ( page 1 )
0x00, // Index = 0x2C ( page 1 )
0x00, // Index = 0x2D ( page 1 )
0x00, // Index = 0x2E ( page 1 )
0x00, // Index = 0x2F ( page 1 )
0x00, // Index = 0x30 ( page 1 )
0x00, // Index = 0x31 ( page 1 )
0x00, // Index = 0x32 ( page 1 )
0x00, // Index = 0x33 ( page 1 )
0x00, // Index = 0x34 ( page 1 )
0x00, // Index = 0x35 ( page 1 )
0x00, // Index = 0x36 ( page 1 )
0x00, // Index = 0x37 ( page 1 )
0x00, // Index = 0x38 ( page 1 )
0x00, // Index = 0x39 ( page 1 )
0x00, // Index = 0x3A ( page 1 )
0x0B, // Index = 0x3B ( page 1 )
0x00, // Index = 0x3C ( page 1 )
0x00, // Index = 0x3D ( page 1 )
0x00, // Index = 0x3E ( page 1 )
0x00, // Index = 0x3F ( page 1 )
0x08, // Index = 0x40 ( page 1 )
0x60, // Index = 0x41 ( page 1 )
0x14, // Index = 0x42 ( page 1 )
0x20, // Index = 0x43 ( page 1 )
0x00, // Index = 0x44 ( page 1 )
0x00, // Index = 0x45 ( page 1 )
0x20, // Index = 0x46 ( page 1 )
0x00, // Index = 0x47 ( page 1 )
0x49, // Index = 0x48 ( page 1 )
0x10, // Index = 0x49 ( page 1 )
0xFF, // Index = 0x4A ( page 1 )
0xFF, // Index = 0x4B ( page 1 )
0xFF, // Index = 0x4C ( page 1 )
0x00, // Index = 0x4D ( page 1 )
0x08, // Index = 0x4E ( page 1 )
0x00, // Index = 0x4F ( page 1 )
0x00, // Index = 0x50 ( page 1 )
0x00, // Index = 0x51 ( page 1 )
0x00, // Index = 0x52 ( page 1 )
0x00, // Index = 0x53 ( page 1 )
0x00, // Index = 0x54 ( page 1 )
0xA0, // Index = 0x55 ( page 1 )
0x00, // Index = 0x56 ( page 1 )
0x00, // Index = 0x57 ( page 1 )
0x00, // Index = 0x58 ( page 1 )
0x00, // Index = 0x59 ( page 1 )
0x00, // Index = 0x5A ( page 1 )
0x7A, // Index = 0x5B ( page 1 )
0x5E, // Index = 0x5C ( page 1 )
0x6E, // Index = 0x5D ( page 1 )
0x1F, // Index = 0x5E ( page 1 )
0x1F, // Index = 0x5F ( page 1 )
0x00, // Index = 0x60 ( page 1 )
0x00, // Index = 0x61 ( page 1 )
0x00, // Index = 0x62 ( page 1 )
0x20, // Index = 0x63 ( page 1 )
0x40, // Index = 0x64 ( page 1 )
0x40, // Index = 0x65 ( page 1 )
0x40, // Index = 0x66 ( page 1 )
0x00, // Index = 0x67 ( page 1 )
0x00, // Index = 0x68 ( page 1 )
0x00, // Index = 0x69 ( page 1 )
0x00, // Index = 0x6A ( page 1 )
0xFF, // Index = 0x6B ( page 1 )
0xFF, // Index = 0x6C ( page 1 )
0xFF, // Index = 0x6D ( page 1 )
0xFF, // Index = 0x6E ( page 1 )
0x50, // Index = 0x6F ( page 1 )
0x00, // Index = 0x70 ( page 1 )
0x00, // Index = 0x71 ( page 1 )
0x09, // Index = 0x72 ( page 1 )
0x00, // Index = 0x73 ( page 1 )
0x00, // Index = 0x74 ( page 1 )
0x70, // Index = 0x75 ( page 1 )
0x00, // Index = 0x76 ( page 1 )
0x50, // Index = 0x77 ( page 1 )
0x00, // Index = 0x78 ( page 1 )
0x98, // Index = 0x79 ( page 1 )
0x00, // Index = 0x7A ( page 1 )
0x98, // Index = 0x7B ( page 1 )
0xFF, // Index = 0x7C ( page 1 )
0x00, // Index = 0x7D ( page 1 )
0x00, // Index = 0x7E ( page 1 )
0x00, // Index = 0x7F ( page 1 )
},
//Page 2:
{
0x56, // Index = 0x00 ( page 2 )
0xF0, // Index = 0x01 ( page 2 )
0xF3, // Index = 0x02 ( page 2 )
0xFF, // Index = 0x03 ( page 2 )
0x36, // Index = 0x04 ( page 2 )
0x58, // Index = 0x05 ( page 2 )
0xAC, // Index = 0x06 ( page 2 )
0xFF, // Index = 0x07 ( page 2 )
0xFF, // Index = 0x08 ( page 2 )
0xFF, // Index = 0x09 ( page 2 )
0xFF, // Index = 0x0A ( page 2 )
0xFF, // Index = 0x0B ( page 2 )
0xFF, // Index = 0x0C ( page 2 )
0xFF, // Index = 0x0D ( page 2 )
0xFF, // Index = 0x0E ( page 2 )
0xFF, // Index = 0x0F ( page 2 )
0xFF, // Index = 0x10 ( page 2 )
0xFF, // Index = 0x11 ( page 2 )
0xFF, // Index = 0x12 ( page 2 )
0xFF, // Index = 0x13 ( page 2 )
0xFF, // Index = 0x14 ( page 2 )
0xFF, // Index = 0x15 ( page 2 )
0xFF, // Index = 0x16 ( page 2 )
0xFF, // Index = 0x17 ( page 2 )
0xFF, // Index = 0x18 ( page 2 )
0xFF, // Index = 0x19 ( page 2 )
0xFF, // Index = 0x1A ( page 2 )
0xFF, // Index = 0x1B ( page 2 )
0xFF, // Index = 0x1C ( page 2 )
0xFF, // Index = 0x1D ( page 2 )
0xFF, // Index = 0x1E ( page 2 )
0xFF, // Index = 0x1F ( page 2 )
0xFF, // Index = 0x20 ( page 2 )
0xFF, // Index = 0x21 ( page 2 )
0xFF, // Index = 0x22 ( page 2 )
0xFF, // Index = 0x23 ( page 2 )
0xFF, // Index = 0x24 ( page 2 )
0xFF, // Index = 0x25 ( page 2 )
0xFF, // Index = 0x26 ( page 2 )
0xFF, // Index = 0x27 ( page 2 )
0xFF, // Index = 0x28 ( page 2 )
0xFF, // Index = 0x29 ( page 2 )
0xFF, // Index = 0x2A ( page 2 )
0xFF, // Index = 0x2B ( page 2 )
0xFF, // Index = 0x2C ( page 2 )
0xFF, // Index = 0x2D ( page 2 )
0xFF, // Index = 0x2E ( page 2 )
0xFF, // Index = 0x2F ( page 2 )
0xFF, // Index = 0x30 ( page 2 )
0xFF, // Index = 0x31 ( page 2 )
0xFF, // Index = 0x32 ( page 2 )
0xFF, // Index = 0x33 ( page 2 )
0xFF, // Index = 0x34 ( page 2 )
0xFF, // Index = 0x35 ( page 2 )
0xFF, // Index = 0x36 ( page 2 )
0xFF, // Index = 0x37 ( page 2 )
0xFF, // Index = 0x38 ( page 2 )
0xFF, // Index = 0x39 ( page 2 )
0xFF, // Index = 0x3A ( page 2 )
0xFF, // Index = 0x3B ( page 2 )
0xFF, // Index = 0x3C ( page 2 )
0xFF, // Index = 0x3D ( page 2 )
0xFF, // Index = 0x3E ( page 2 )
0xFF, // Index = 0x3F ( page 2 )
0xFF, // Index = 0x40 ( page 2 )
0xFF, // Index = 0x41 ( page 2 )
0xFF, // Index = 0x42 ( page 2 )
0xFF, // Index = 0x43 ( page 2 )
0xFF, // Index = 0x44 ( page 2 )
0xFF, // Index = 0x45 ( page 2 )
0xFF, // Index = 0x46 ( page 2 )
0xFF, // Index = 0x47 ( page 2 )
0xFF, // Index = 0x48 ( page 2 )
0xFF, // Index = 0x49 ( page 2 )
0xFF, // Index = 0x4A ( page 2 )
0xFF, // Index = 0x4B ( page 2 )
0xFF, // Index = 0x4C ( page 2 )
0xFF, // Index = 0x4D ( page 2 )
0xFF, // Index = 0x4E ( page 2 )
0xFF, // Index = 0x4F ( page 2 )
0xFF, // Index = 0x50 ( page 2 )
0xFF, // Index = 0x51 ( page 2 )
0xFF, // Index = 0x52 ( page 2 )
0xFF, // Index = 0x53 ( page 2 )
0xFF, // Index = 0x54 ( page 2 )
0xFF, // Index = 0x55 ( page 2 )
0xFF, // Index = 0x56 ( page 2 )
0xFF, // Index = 0x57 ( page 2 )
0xFF, // Index = 0x58 ( page 2 )
0xFF, // Index = 0x59 ( page 2 )
0xFF, // Index = 0x5A ( page 2 )
0xFF, // Index = 0x5B ( page 2 )
0xFF, // Index = 0x5C ( page 2 )
0xFF, // Index = 0x5D ( page 2 )
0xFF, // Index = 0x5E ( page 2 )
0xFF, // Index = 0x5F ( page 2 )
0xFF, // Index = 0x60 ( page 2 )
0xFF, // Index = 0x61 ( page 2 )
0xFF, // Index = 0x62 ( page 2 )
0xFF, // Index = 0x63 ( page 2 )
0xFF, // Index = 0x64 ( page 2 )
0xFF, // Index = 0x65 ( page 2 )
0xFF, // Index = 0x66 ( page 2 )
0xFF, // Index = 0x67 ( page 2 )
0xFF, // Index = 0x68 ( page 2 )
0xFF, // Index = 0x69 ( page 2 )
0xFF, // Index = 0x6A ( page 2 )
0xFF, // Index = 0x6B ( page 2 )
0xFF, // Index = 0x6C ( page 2 )
0xFF, // Index = 0x6D ( page 2 )
0xFF, // Index = 0x6E ( page 2 )
0xFF, // Index = 0x6F ( page 2 )
0xFF, // Index = 0x70 ( page 2 )
0xFF, // Index = 0x71 ( page 2 )
0xFF, // Index = 0x72 ( page 2 )
0xFF, // Index = 0x73 ( page 2 )
0xFF, // Index = 0x74 ( page 2 )
0xFF, // Index = 0x75 ( page 2 )
0xFF, // Index = 0x76 ( page 2 )
0xFF, // Index = 0x77 ( page 2 )
0xFF, // Index = 0x78 ( page 2 )
0xFF, // Index = 0x79 ( page 2 )
0xFF, // Index = 0x7A ( page 2 )
0xFF, // Index = 0x7B ( page 2 )
0xFF, // Index = 0x7C ( page 2 )
0xFF, // Index = 0x7D ( page 2 )
0xFF, // Index = 0x7E ( page 2 )
0xFF, // Index = 0x7F ( page 2 )
},
//Page 3:
{
0x56, // Index = 0x00 ( page 3 )
0xF0, // Index = 0x01 ( page 3 )
0xF3, // Index = 0x02 ( page 3 )
0x03, // Index = 0x03 ( page 3 )
0x36, // Index = 0x04 ( page 3 )
0x58, // Index = 0x05 ( page 3 )
0xAC, // Index = 0x06 ( page 3 )
0x00, // Index = 0x07 ( page 3 )
0x00, // Index = 0x08 ( page 3 )
0x00, // Index = 0x09 ( page 3 )
0x00, // Index = 0x0A ( page 3 )
0x00, // Index = 0x0B ( page 3 )
0xFF, // Index = 0x0C ( page 3 )
0x00, // Index = 0x0D ( page 3 )
0x03, // Index = 0x0E ( page 3 )
0x19, // Index = 0x0F ( page 3 )
0x40, // Index = 0x10 ( page 3 )
0x00, // Index = 0x11 ( page 3 )
0x00, // Index = 0x12 ( page 3 )
0x00, // Index = 0x13 ( page 3 )
0x00, // Index = 0x14 ( page 3 )
0x00, // Index = 0x15 ( page 3 )
0x00, // Index = 0x16 ( page 3 )
0x00, // Index = 0x17 ( page 3 )
0x00, // Index = 0x18 ( page 3 )
0x00, // Index = 0x19 ( page 3 )
0x00, // Index = 0x1A ( page 3 )
0x00, // Index = 0x1B ( page 3 )
0x00, // Index = 0x1C ( page 3 )
0x00, // Index = 0x1D ( page 3 )
0x00, // Index = 0x1E ( page 3 )
0x00, // Index = 0x1F ( page 3 )
0x00, // Index = 0x20 ( page 3 )
0x00, // Index = 0x21 ( page 3 )
0x00, // Index = 0x22 ( page 3 )
0x00, // Index = 0x23 ( page 3 )
0x00, // Index = 0x24 ( page 3 )
0x11, // Index = 0x25 ( page 3 )
0xFF, // Index = 0x26 ( page 3 )
0xFF, // Index = 0x27 ( page 3 )
0xFF, // Index = 0x28 ( page 3 )
0xFF, // Index = 0x29 ( page 3 )
0xFF, // Index = 0x2A ( page 3 )
0xFF, // Index = 0x2B ( page 3 )
0xFF, // Index = 0x2C ( page 3 )
0xFF, // Index = 0x2D ( page 3 )
0xFF, // Index = 0x2E ( page 3 )
0xFF, // Index = 0x2F ( page 3 )
0xFF, // Index = 0x30 ( page 3 )
0xFF, // Index = 0x31 ( page 3 )
0xFF, // Index = 0x32 ( page 3 )
0xFF, // Index = 0x33 ( page 3 )
0xFF, // Index = 0x34 ( page 3 )
0xFF, // Index = 0x35 ( page 3 )
0xFF, // Index = 0x36 ( page 3 )
0xFF, // Index = 0x37 ( page 3 )
0xFF, // Index = 0x38 ( page 3 )
0xFF, // Index = 0x39 ( page 3 )
0xFF, // Index = 0x3A ( page 3 )
0xFF, // Index = 0x3B ( page 3 )
0xFF, // Index = 0x3C ( page 3 )
0xFF, // Index = 0x3D ( page 3 )
0xFF, // Index = 0x3E ( page 3 )
0xFF, // Index = 0x3F ( page 3 )
0xFF, // Index = 0x40 ( page 3 )
0x09, // Index = 0x41 ( page 3 )
0x1D, // Index = 0x42 ( page 3 )
0x0F, // Index = 0x43 ( page 3 )
0x00, // Index = 0x44 ( page 3 )
0xFF, // Index = 0x45 ( page 3 )
0xFF, // Index = 0x46 ( page 3 )
0xFF, // Index = 0x47 ( page 3 )
0xFF, // Index = 0x48 ( page 3 )
0xFF, // Index = 0x49 ( page 3 )
0xFF, // Index = 0x4A ( page 3 )
0xFF, // Index = 0x4B ( page 3 )
0xFF, // Index = 0x4C ( page 3 )
0xFF, // Index = 0x4D ( page 3 )
0xFF, // Index = 0x4E ( page 3 )
0xFF, // Index = 0x4F ( page 3 )
0xFF, // Index = 0x50 ( page 3 )
0xFF, // Index = 0x51 ( page 3 )
0xFF, // Index = 0x52 ( page 3 )
0xFF, // Index = 0x53 ( page 3 )
0xFF, // Index = 0x54 ( page 3 )
0xFF, // Index = 0x55 ( page 3 )
0xFF, // Index = 0x56 ( page 3 )
0xFF, // Index = 0x57 ( page 3 )
0xFF, // Index = 0x58 ( page 3 )
0xFF, // Index = 0x59 ( page 3 )
0xFF, // Index = 0x5A ( page 3 )
0xFF, // Index = 0x5B ( page 3 )
0xFF, // Index = 0x5C ( page 3 )
0xFF, // Index = 0x5D ( page 3 )
0xFF, // Index = 0x5E ( page 3 )
0xFF, // Index = 0x5F ( page 3 )
0xFF, // Index = 0x60 ( page 3 )
0xFF, // Index = 0x61 ( page 3 )
0xFF, // Index = 0x62 ( page 3 )
0xFF, // Index = 0x63 ( page 3 )
0xFF, // Index = 0x64 ( page 3 )
0xFF, // Index = 0x65 ( page 3 )
0xFF, // Index = 0x66 ( page 3 )
0xFF, // Index = 0x67 ( page 3 )
0xFF, // Index = 0x68 ( page 3 )
0xFF, // Index = 0x69 ( page 3 )
0xFF, // Index = 0x6A ( page 3 )
0xFF, // Index = 0x6B ( page 3 )
0xFF, // Index = 0x6C ( page 3 )
0xFF, // Index = 0x6D ( page 3 )
0x00, // Index = 0x6E ( page 3 )
0x00, // Index = 0x6F ( page 3 )
0xFF, // Index = 0x70 ( page 3 )
0xF8, // Index = 0x71 ( page 3 )
0xFF, // Index = 0x72 ( page 3 )
0x00, // Index = 0x73 ( page 3 )
0x02, // Index = 0x74 ( page 3 )
0xFF, // Index = 0x75 ( page 3 )
0x00, // Index = 0x76 ( page 3 )
0x00, // Index = 0x77 ( page 3 )
0x00, // Index = 0x78 ( page 3 )
0xFF, // Index = 0x79 ( page 3 )
0xFF, // Index = 0x7A ( page 3 )
0xFF, // Index = 0x7B ( page 3 )
0xFF, // Index = 0x7C ( page 3 )
0xFF, // Index = 0x7D ( page 3 )
0xFF, // Index = 0x7E ( page 3 )
0xFF, // Index = 0x7F ( page 3 )
},
//Page 4:
{
0x56, // Index = 0x00 ( page 4 )
0xF0, // Index = 0x01 ( page 4 )
0xF3, // Index = 0x02 ( page 4 )
0x04, // Index = 0x03 ( page 4 )
0x36, // Index = 0x04 ( page 4 )
0x58, // Index = 0x05 ( page 4 )
0xAC, // Index = 0x06 ( page 4 )
0xFF, // Index = 0x07 ( page 4 )
0x00, // Index = 0x08 ( page 4 )
0x00, // Index = 0x09 ( page 4 )
0x00, // Index = 0x0A ( page 4 )
0x00, // Index = 0x0B ( page 4 )
0x00, // Index = 0x0C ( page 4 )
0x00, // Index = 0x0D ( page 4 )
0xC0, // Index = 0x0E ( page 4 )
0x00, // Index = 0x0F ( page 4 )
0x00, // Index = 0x10 ( page 4 )
0x00, // Index = 0x11 ( page 4 )
0x00, // Index = 0x12 ( page 4 )
0x00, // Index = 0x13 ( page 4 )
0x00, // Index = 0x14 ( page 4 )
0x00, // Index = 0x15 ( page 4 )
0x00, // Index = 0x16 ( page 4 )
0x00, // Index = 0x17 ( page 4 )
0xFF, // Index = 0x18 ( page 4 )
0xFF, // Index = 0x19 ( page 4 )
0xFF, // Index = 0x1A ( page 4 )
0xFF, // Index = 0x1B ( page 4 )
0xFF, // Index = 0x1C ( page 4 )
0xFF, // Index = 0x1D ( page 4 )
0xFF, // Index = 0x1E ( page 4 )
0xFF, // Index = 0x1F ( page 4 )
0xFF, // Index = 0x20 ( page 4 )
0xFF, // Index = 0x21 ( page 4 )
0xFF, // Index = 0x22 ( page 4 )
0xFF, // Index = 0x23 ( page 4 )
0xFF, // Index = 0x24 ( page 4 )
0xFF, // Index = 0x25 ( page 4 )
0xFF, // Index = 0x26 ( page 4 )
0xFF, // Index = 0x27 ( page 4 )
0x00, // Index = 0x28 ( page 4 )
0x00, // Index = 0x29 ( page 4 )
0x4F, // Index = 0x2A ( page 4 )
0x07, // Index = 0x2B ( page 4 )
0x4F, // Index = 0x2C ( page 4 )
0x07, // Index = 0x2D ( page 4 )
0x3B, // Index = 0x2E ( page 4 )
0x07, // Index = 0x2F ( page 4 )
0x3B, // Index = 0x30 ( page 4 )
0x07, // Index = 0x31 ( page 4 )
0x50, // Index = 0x32 ( page 4 )
0x00, // Index = 0x33 ( page 4 )
0x50, // Index = 0x34 ( page 4 )
0x00, // Index = 0x35 ( page 4 )
0x10, // Index = 0x36 ( page 4 )
0x00, // Index = 0x37 ( page 4 )
0x00, // Index = 0x38 ( page 4 )
0x10, // Index = 0x39 ( page 4 )
0x00, // Index = 0x3A ( page 4 )
0x00, // Index = 0x3B ( page 4 )
0x00, // Index = 0x3C ( page 4 )
0x00, // Index = 0x3D ( page 4 )
0x00, // Index = 0x3E ( page 4 )
0x00, // Index = 0x3F ( page 4 )
0x00, // Index = 0x40 ( page 4 )
0xFF, // Index = 0x41 ( page 4 )
0xFF, // Index = 0x42 ( page 4 )
0xFF, // Index = 0x43 ( page 4 )
0xFF, // Index = 0x44 ( page 4 )
0x00, // Index = 0x45 ( page 4 )
0x03, // Index = 0x46 ( page 4 )
0x00, // Index = 0x47 ( page 4 )
0x00, // Index = 0x48 ( page 4 )
0x00, // Index = 0x49 ( page 4 )
0x24, // Index = 0x4A ( page 4 )
0x00, // Index = 0x4B ( page 4 )
0x40, // Index = 0x4C ( page 4 )
0xFF, // Index = 0x4D ( page 4 )
0xFF, // Index = 0x4E ( page 4 )
0x7F, // Index = 0x4F ( page 4 )
0x56, // Index = 0x50 ( page 4 )
0x80, // Index = 0x51 ( page 4 )
0x3F, // Index = 0x52 ( page 4 )
0x00, // Index = 0x53 ( page 4 )
0x84, // Index = 0x54 ( page 4 )
0x60, // Index = 0x55 ( page 4 )
0xAF, // Index = 0x56 ( page 4 )
0x00, // Index = 0x57 ( page 4 )
0x00, // Index = 0x58 ( page 4 )
0x80, // Index = 0x59 ( page 4 )
0x94, // Index = 0x5A ( page 4 )
0x00, // Index = 0x5B ( page 4 )
0x80, // Index = 0x5C ( page 4 )
0x00, // Index = 0x5D ( page 4 )
0x05, // Index = 0x5E ( page 4 )
0x38, // Index = 0x5F ( page 4 )
0x01, // Index = 0x60 ( page 4 )
0x83, // Index = 0x61 ( page 4 )
0x11, // Index = 0x62 ( page 4 )
0x01, // Index = 0x63 ( page 4 )
0x80, // Index = 0x64 ( page 4 )
0x90, // Index = 0x65 ( page 4 )
0x00, // Index = 0x66 ( page 4 )
0x40, // Index = 0x67 ( page 4 )
0x4A, // Index = 0x68 ( page 4 )
0xE4, // Index = 0x69 ( page 4 )
0x00, // Index = 0x6A ( page 4 )
0x00, // Index = 0x6B ( page 4 )
0x00, // Index = 0x6C ( page 4 )
0x00, // Index = 0x6D ( page 4 )
0x89, // Index = 0x6E ( page 4 )
0x10, // Index = 0x6F ( page 4 )
0xAC, // Index = 0x70 ( page 4 )
0x00, // Index = 0x71 ( page 4 )
0xE0, // Index = 0x72 ( page 4 )
0x80, // Index = 0x73 ( page 4 )
0x80, // Index = 0x74 ( page 4 )
0x19, // Index = 0x75 ( page 4 )
0x7D, // Index = 0x76 ( page 4 )
0x00, // Index = 0x77 ( page 4 )
0xFF, // Index = 0x78 ( page 4 )
0xFF, // Index = 0x79 ( page 4 )
0xFF, // Index = 0x7A ( page 4 )
0xFF, // Index = 0x7B ( page 4 )
0xFF, // Index = 0x7C ( page 4 )
0xFF, // Index = 0x7D ( page 4 )
0x00, // Index = 0x7E ( page 4 )
0x0C, // Index = 0x7F ( page 4 )
},
};
static unsigned char GenDefault(int p, int r)
{
if ((p < 5) && (r < 128))
return g_DefRegMap[p][r];
return 0;
}
static int smbus_write_byte_data(int dev, int reg, int data)
{
struct i2c_smbus_ioctl_data iodata;
union i2c_smbus_data value;
int res;
if (dev < 0) {
printf("WR_%d {0x%02x, 0x%02x} -> %d\n", ch7036_cur_page, reg, data, 0);
return 0;
}
value.byte = data;
iodata.read_write = I2C_SMBUS_WRITE;
iodata.command = reg;
iodata.size = I2C_SMBUS_BYTE_DATA;
iodata.data = &value;
res = ioctl(dev, I2C_SMBUS, &iodata);
if (res < 0)
fprintf(stderr, "Write byte fail (%d, %02x, %02x): %s",
dev, reg, data, strerror(errno));
if (ch7036_debugi2c)
printf("WR_%d {0x%02x, 0x%02x} -> %d\n", ch7036_cur_page, reg, data, res);
return res;
}
static int smbus_write_word_data(int dev, int reg, int data)
{
struct i2c_smbus_ioctl_data iodata;
union i2c_smbus_data value;
int res;
if (dev < 0) {
printf("WR_%d {0x%02x, 0x%04x} -> %d\n", ch7036_cur_page, reg, data, 0);
return 0;
}
value.word = data;
iodata.read_write = I2C_SMBUS_WRITE;
iodata.command = reg;
iodata.size = I2C_SMBUS_WORD_DATA;
iodata.data = &value;
res = ioctl(dev, I2C_SMBUS, &iodata);
if (res < 0)
fprintf(stderr, "Write word fail (%d, %04x, %02x): %s",
dev, reg, data, strerror(errno));
if (ch7036_debugi2c)
printf("WR_%d {0x%02x, 0x%04x} -> %d\n", ch7036_cur_page, reg, data, res);
return res;
}
#ifdef FASTLOAD
static int smbus_write_reg_bytes(int dev, int reg, int size,
unsigned char *data)
{
struct i2c_smbus_ioctl_data iodata;
union i2c_smbus_data value;
int res;
if (size > I2C_SMBUS_BLOCK_MAX) {
fprintf(stderr, "Bad call to smbus_write_reg_bytes with size %d\n", size);
return -1;
}
if (dev < 0) {
printf("WR_%d {0x%02x, 0x%02x,...[%d]} -> %d\n",
ch7036_cur_page, reg, data[0], size, 0);
return 0;
}
memcpy(&value.block[1], data, size);
value.block[0] = size;
iodata.read_write = I2C_SMBUS_WRITE;
iodata.command = reg;
iodata.size = I2C_SMBUS_I2C_BLOCK_DATA;
iodata.data = &value;
res = ioctl(dev, I2C_SMBUS, &iodata);
if (res < 0)
fprintf(stderr, "Write bytes fail (%d, %02x, %02x,...[%d]): %s\n",
dev, reg, data[0], size, strerror(errno));
if (ch7036_debugi2c)
printf("WR_%d {0x%02x, 0x%02x,...[%d]} -> %d\n",
ch7036_cur_page, reg, data[0], size, res);
return res;
}
#endif
static int smbus_read_byte_data(int dev, int reg)
{
struct i2c_smbus_ioctl_data iodata;
union i2c_smbus_data value;
if (dev < 0) {
printf("RD_%d {0x%02x} -> 0x%02x\n", ch7036_cur_page, reg, 0);
return 0;
}
iodata.read_write = I2C_SMBUS_READ;
iodata.command = reg;
iodata.size = I2C_SMBUS_BYTE_DATA;
iodata.data = &value;
if (ioctl(dev, I2C_SMBUS, &iodata) < 0) {
fprintf(stderr, "Read byte fail (%d, %02x): %s",
dev, reg, strerror(errno));
return -1;
}
if (ch7036_debugi2c)
printf("RD_%d {0x%02x} -> 0x%02x\n", ch7036_cur_page, reg, value.byte);
return value.byte;
}
int ch_write_reg(int dev, int page, int reg, int data)
{
int res;
if (((page < 1) || (page > 4)) && (reg != CH7036_PAGE))
return -1;
if ((page != ch7036_cur_page) && (reg != CH7036_PAGE)) {
if (ch_write_reg(dev, ch7036_cur_page, CH7036_PAGE, ch_page_map[page]) < 0)
return -1;
}
res = smbus_write_byte_data(dev, reg, data);
if (res < 0)
return -1;
if (reg == CH7036_PAGE) {
ch7036_cur_page = ch_page_revmap[data & 7];
}
return 0;
}
int ch_read_reg(int dev, int page, int reg)
{
int res;
if ((page < 1) || (page > 4))
return -1;
if (page != ch7036_cur_page) {
if (ch_write_reg(dev, ch7036_cur_page, CH7036_PAGE, ch_page_map[page]) < 0)
return -1;
}
res = smbus_read_byte_data(dev, reg);
return res;
}
int ch_write_reg_sequence (int dev, struct reg_ch7036* seq)
{
int i, res;
int n_regs = N_REGS_IN_SEQ(seq);
for (i=1; i <= n_regs; i++) {
res = smbus_write_byte_data(dev, seq[i].index, seq[i].value);
changed[ch_page_map[ch7036_cur_page]][seq[i].index] = 1;
if (res < 0)
return -1;
if (seq[i].index == CH7036_PAGE)
ch7036_cur_page = ch_page_revmap[seq[i].value & 7];
}
return 0;
}
int ch_restore_notin_seq (int dev, struct reg_ch7036* seq, int verbose)
{
int i, j;
int n_regs = N_REGS_IN_SEQ(seq);
int loc_cp = ch7036_cur_page;
int err;
int nwritten = 0;
/* Clear the changed vector for anything we are about to write */
for (i=1; i <= n_regs; i++) {
changed[ch_page_map[loc_cp]][seq[i].index] = 0;
if (seq[i].index == CH7036_PAGE)
loc_cp = ch_page_revmap[seq[i].value & 7];
}
for(j=0; j < 5; j++)
for(i=0; i < 128; i++) if (changed[j][i]) {
if (i == CH7036_PAGE) continue;
err = ch_write_reg(dev, ch_page_revmap[j], i, GenDefault(j, i));
if (err != 0) return err;
// Now at default, so it is no longer changed
changed[j][i] = 0;
nwritten++;
}
if (verbose)
printf("... Restored %d registers\n", nwritten);
return 0;
}
int ch_remove_last_reg(struct reg_ch7036* seq, int page, int reg)
{
int i;
int n_regs = N_REGS_IN_SEQ(seq);
int cp = -1;
int last_found = -1;
/* Some registers are in the list multiple times */
/* Need to remove the last one */
/* But must parse forward to follow page changes */
for (i=1; i <= n_regs; i++) {
if ((cp == page) && (seq[i].index == reg))
last_found = i;
if (seq[i].index == CH7036_PAGE)
cp = ch_page_revmap[seq[i].value & 7];
}
if (last_found > 0) {
int ov = seq[last_found].value;
for (i=last_found; i < n_regs; i++) seq[i] = seq[i+1];
n_regs--;
seq[0].index = (n_regs >> 8);
seq[0].value = (n_regs & 0xff);
return ov;
}
return -1;
}
int ch_change_reg(struct reg_ch7036* seq, int page, int reg,
int andv, int orv)
{
int i;
int n_regs = N_REGS_IN_SEQ(seq);
int cp = -1;
int last_found = -1;
/* Some registers are in the list multiple times */
/* Need to modify the last one to have an effect */
/* But must parse forward to follow page changes */
for (i=1; i <= n_regs; i++) {
if ((cp == page) && (seq[i].index == reg))
last_found = i;
if (seq[i].index == CH7036_PAGE)
cp = ch_page_revmap[seq[i].value & 7];
}
if (last_found > 0) {
int ov = seq[last_found].value;
seq[last_found].value = (ov & andv) | orv;
return ov;
}
return -1;
}
void ch_reset_datapath (int dev)
{
int res = ch_read_reg(dev, CH7036_RESET);
/* Reset the datapath then remove reset */
ch_write_reg(dev, CH7036_RESET, res & ~0x1);
ch_write_reg(dev, CH7036_RESET, res | 0x1);
}
/* Email from Chrontel 5/20 to reset to defaults */
/* Note: will need to redo step1 after this! */
void ch_reset_todefault (int dev)
{
int i;
int res = ch_read_reg(dev, CH7036_RESET);
/* Reset registers then remove reset */
ch_write_reg(dev, CH7036_RESET, res & ~0x2);
ch_write_reg(dev, CH7036_RESET, res | 0x2);
for(i=0; i < 256; i++)
changed[0][i] = changed[1][i] = changed[2][i] =
changed[3][i] = changed[4][i] = 0;
}
/* Turn the monitor on */
void ch_monitor_on(int dev, int hdmi_out, int verbose)
{
int old;
int needed_bit_value;
ch_write_reg(dev, CH7036_PWRST2, 0xD0); // HDMI driver, SDRAM. SPDIF on
ch_write_reg(dev, CH7036_PWRST3, 0x0F); // VGA dac powered down
ch_write_reg(dev, CH7036_PWRST4, 0x02); // SDRAM, HDMI power on, RGB off
ch_write_reg(dev, CH7036_MAGIC2_0E, 0x13); // MAGIC
ch_write_reg(dev, CH7036_SDTIME1, 0x20);
ch_write_reg(dev, CH7036_PWRSTATE1, 0x84); // Normal (pll on)
ch_reset_datapath(dev);
/* reset datapath seems to mess with this bit with some fw revs */
needed_bit_value = hdmi_out ? 0x04 : 0;
old = ch_read_reg(dev, CH7036_PWRST5);
if ((old & 0x04) != needed_bit_value) {
if (verbose) printf("Need %sI out: change PWRST5 from 0x%x to 0x%x\n",
hdmi_out ? "HDM" : "DV",
old, (old & ~0x04) | needed_bit_value);
ch_write_reg(dev, CH7036_PWRST5, (old & ~0x04) | needed_bit_value);
}
}
/* Turn the monitor off */
void ch_monitor_off(int dev)
{
ch_write_reg(dev, CH7036_PWRST2, 0xDF); // HDMI driver, SDRAM. SPDIF off
ch_write_reg(dev, CH7036_PWRST3, 0xFF); // VGA dac powered down
ch_write_reg(dev, CH7036_PWRST4, 0x7F); // Stop hdmi,scaler, pwr down
ch_write_reg(dev, CH7036_MAGIC2_0E, 0x93); // MAGIC
ch_write_reg(dev, CH7036_SDTIME1, 0x29); // HDMI driver, PLL power off
ch_write_reg(dev, CH7036_PWRSTATE1, 0x94); // pll power down
}
/* Turn the monitor off but keep DDC running so EDID can still be read */
void ch_monitor_off_keep_ddc(int dev)
{
ch_write_reg(dev, CH7036_PWRST2, 0xDF); // HDMI driver, SDRAM. SPDIF off
ch_write_reg(dev, CH7036_PWRST3, 0xFF); // VGA dac powered down
ch_write_reg(dev, CH7036_PWRST4, 0x7F); // Stop hdmi,scaler, pwr down
/* Chrontel email response 2010-06-17 to Off preventing EDID reads */
/* Please remove both 0xE and 0x16 registers */
/* 0xE will power down DDC */
ch_write_reg(dev, CH7036_PWRSTATE1, 0x94); // pll power down
}
int ch_hdmi_is_on(int dev)
{
int res;
res = ch_read_reg(dev, CH7036_PWRST2);
if (res < 0) {
fprintf(stderr, "Failed to read powerstate 2 to check hdmi on\n");
return 0;
}
/* Check if HDMI driver is powered down (bit set) */
return (res & 0x8) ? 0 : 1;
}
/* Calculate INC registers from values the chip provides */
void ch_calculate_incs(int dev)
{
unsigned int hinca, hincb, hinc;
unsigned int vinca, vincb, vinc;
unsigned int hdinca, hdincb, hdinc;
//first read out parameters:
hinca = ((ch_read_reg(dev, CH7036_HINCA1) << 3) |
(ch_read_reg(dev, CH7036_HINCA2) & 0x7));
hincb = ((ch_read_reg(dev, CH7036_HINCB1) << 3) |
(ch_read_reg(dev, CH7036_HINCB2) & 0x7));
vinca = ((ch_read_reg(dev, CH7036_VINCA1) << 3) |
(ch_read_reg(dev, CH7036_VINCA2) & 0x7));
vincb = ((ch_read_reg(dev, CH7036_VINCB1) << 3) |
(ch_read_reg(dev, CH7036_VINCB2) & 0x7));
hdinca = ((ch_read_reg(dev, CH7036_HDINCA1) << 3) |
(ch_read_reg(dev, CH7036_HDINCA2) & 0x7));
hdincb = ((ch_read_reg(dev, CH7036_HDINCB1) << 3) |
(ch_read_reg(dev, CH7036_HDINCB2) & 0x7));
/* calculate them */
/* NOTE: this code works because the values are 11-bit */
/* so the shift in a 32-bit uint will not drop any bits from the top */
if (hinca == 0 || hincb == 0) {
hinc = 0;
} else {
hinc = (1 << 20) * hinca / hincb;
}
if (vinca == 0 || vincb == 0) {
vinc = 0;
} else {
vinc = (1 << 20) * vinca / vincb;
}
if (hdinca == 0 || hdincb == 0) {
hdinc = 0;
} else {
hdinc = (1 << 20) * hdinca / hdincb;
}
ch_write_reg(dev, CH7036_HINCC1,(hinc>>16) & 0xFF);
ch_write_reg(dev, CH7036_HINCC2,(hinc>>8) & 0xFF);
ch_write_reg(dev, CH7036_HINCC3, hinc & 0xFF);
ch_write_reg(dev, CH7036_VINCC1,(vinc>>16) & 0xFF);
ch_write_reg(dev, CH7036_VINCC2,(vinc>>8) & 0xFF);
ch_write_reg(dev, CH7036_VINCC3, vinc & 0xFF);
ch_write_reg(dev, CH7036_HDINCC1,(hdinc>>16) & 0xFF);
ch_write_reg(dev, CH7036_HDINCC2,(hdinc>>8) & 0xFF);
ch_write_reg(dev, CH7036_HDINCC3, hdinc & 0xFF);
}
int ch_suspend_firmware(int dev, int verbose)
{
int res = ch_read_reg(dev, CH7036_RESET);
res &= ~0x4;
if (verbose) printf("Suspend CH7036 firmware, set RESET to 0x%x\n", res);
ch_write_reg(dev, CH7036_RESET, res);
return res;
}
int ch_release_firmware(int dev, int verbose)
{
int res = ch_read_reg(dev, CH7036_RESET);
res |= 0x4;
if (verbose) printf("Release CH7036 firmware, set RESET to 0x%x\n", res);
ch_write_reg(dev, CH7036_RESET, res);
return res;
}
/* Load Firmware */
int ch_load_firmware(int dev, char* fname)
{
unsigned char buf[10240];
FILE* fp;
long fs, fs1;
int res = -1;
do {
fp = fopen(fname, "rb");
if (fp==NULL) {
fprintf(stderr, "Could not open %s to read firmware\n", fname);
break;
}
fseek( fp, 0, SEEK_END);
fs = ftell(fp);
fseek( fp, 0, SEEK_SET);
fs1 = fread( buf, 1, fs, fp);
if (fs1 != fs) {
printf("File %s reading error!\n", fname);
break;
}
printf("Firmware size = %d bytes.\n", (int)fs);
/* Initialize the firmware download */
ch_write_reg(dev, 4, 0x52, 0x2b);
ch_write_reg(dev, 4, 0x5b, 0x9e);
ch_write_reg(dev, 4, 0x5b, 0xb3);
smbus_write_byte_data(dev, 0x03, 0x07);
/* Download the firmware */
/* "The downloading can be byte by byte, or using I2C block write" */
/* FIXME mdhayter: Did not get the block write to work with count > 1 */
/* The SMBus hangs completely using I2C_SMBUS_I2C_BLOCK which is the */
/* version that does not send the length required by Chrontel (unless */
/* the length is set to 1). The transfers complete ok using the */
/* I2C_SMBUS_BLOCK version, but the firmware is no good (as expected) */
/* Could it be the kernel driver? */
/* Using word seems ok and halves the number of transactions */
#ifdef SLOWLOAD
for (fs1=0; fs1<fs; fs1++)
smbus_write_byte_data(dev, 0x07, buf[fs1]);
#endif
#ifndef FASTLOAD
for(fs1 = 0; (fs1+1) < fs; fs1+=2)
smbus_write_word_data(dev, 0x07, buf[fs1] | (buf[fs1+1]<<8));
if (fs1 < fs)
smbus_write_byte_data(dev, 0x07, buf[fs1]);
#else
#define TXSIZE 32
for(fs1 = 0; (fs1+TXSIZE) < fs; fs1+=TXSIZE)
smbus_write_reg_bytes(dev, 0x07, TXSIZE, buf+fs1);
if (fs1 < fs)
smbus_write_reg_bytes(dev, 0x07, fs-fs1, buf+fs1);
#endif
/* Finishing the download and run the firmware */
smbus_write_byte_data(dev, 0x03, 0x04);
smbus_write_byte_data(dev, 0x52, 0x2F);
smbus_write_byte_data(dev, 0x03, 0x00);
ch7036_cur_page = -1;
res = 0;
} while(0);
if (fp!=NULL) fclose(fp);
return res;
}
/* Note -- this only works if firmware is loaded */
/* will time out if the firmware is not running */
int ch_mcu_version(int dev, int newFirmware, int verbose)
{
unsigned char data[16];
FW7036_CFG *config = (FW7036_CFG *) &data[0];
struct timeval tv;
/* This timeout needs to be tuned. 500,000 works but is a bit */
/* long when trying to detect the firmware going away */
/* 100,000 seems to sometimes give false timeouts */
/* 200,000 is good except when the firmware is restarting */
struct timeval tout = {0, 200000};
if (newFirmware) tout.tv_usec = 500000;
ch7036_cur_page = -1;
// Send Host Request
smbus_write_byte_data(dev, 0x03, 0x00);
smbus_write_byte_data(dev, 0x4F, 0x5F);
// Wait the MCU response
gettimeofday(&tv, NULL);
timeradd(&tv, &tout, &tout);
while (1) {
smbus_write_byte_data(dev, 0x03, 0x00);
if (((0x7F & smbus_read_byte_data(dev, 0x4F))==0x1F) || (dev < 0)) {
int i;
smbus_write_byte_data(dev, 0x03, MCU_DATA_PAGE);
for (i=0; i<sizeof(FW7036_CFG); i++) {
// data[16] holds the return parameter block from MCU
data[i] = smbus_read_byte_data(dev, es_map[i]);
}
smbus_write_byte_data(dev, 0x03, 0x00);
break;
}
gettimeofday(&tv, NULL);
if (timercmp(&tv, &tout, >)) {
fprintf(stderr, "Timeout waiting for MCU version\n");
return -1;
}
}
if (verbose)
printf("CH7036 MCU ver %d.%d, Device %02x rev %d, capability 0x%x\n",
config->ver_major, config->ver_minor,
config->did, config->rid, config->capbility);
return (config->ver_major<<8) | config->ver_minor;
}
/* Note -- this only works if firmware is loaded */
/* Always says hdmi detected if firmware is not loaded */
int ch_hdmi_detected(int dev)
{
int res;
res = ch_read_reg(dev, CH7036_HDMI_ST);
if (res < 0) return res;
res = (res & 0x10) ? 1 : 0;
return res;
}
/* The hdmi detect can be read directly from a gpio */
/* The Linux GPIO sysfs file reads as ascii '0' or '1' */
/* This function returns 1 = connected, 0 = not connected or error */
int ch_hdmi_gpio_detected(int gpiodev, int verbose)
{
int err;
char buff[2];
err = lseek(gpiodev, 0, SEEK_SET);
if (err != 0) {
fprintf(stderr, "gpiodev(%d): lseek returned %d (%s)",
gpiodev, err, (err < 0) ? strerror(errno) : "Not at start");
return 0;
}
err = read(gpiodev, buff, 1);
if (err != 1) {
fprintf(stderr, "gpiodev(%d): read returned %d (%s)",
gpiodev, err, (err < 0) ? strerror(errno) : "More than 1 byte");
return 0;
}
if ((buff[0] != '0') && (buff[0] != '1')) {
fprintf(stderr, "gpiodev(%d): read gave unexpected character %c (0x%02x)\n",
gpiodev, buff[0], buff[0]);
return 0;
}
if (verbose) printf("HDMI GPIO read as %c\n", buff[0]);
return (buff[0] == '1');
}
/* Note -- this only works if firmware is loaded */
/* will time out if the firmware is not running */
int ch_get_edid(int dev, int edid_block, unsigned char* edid)
{
int j;
int res;
struct timeval tv;
struct timeval tout = {0, 500000};
ch7036_cur_page = -1;
// edid_block
for (j=0; j<8; j++) {
// Send Host Request
res = smbus_write_byte_data(dev, 0x03, 0x00);
if (res < 0) return res;
// one edid block contains 128 bytes, so we need read 8 blocks
res = smbus_write_byte_data(dev, 0x50, ((edid_block*8)+j));
if (res < 0) return res;
res = smbus_write_byte_data(dev, 0x4F, 0x41);
if (res < 0) return res;
// Wait the MCU response
gettimeofday(&tv, NULL);
timeradd(&tv, &tout, &tout);
while (1) {
res = smbus_write_byte_data(dev, 0x03, 0x00);
if (res < 0) return res;
// Order in dummy case should do one read...
if (((0x7F & smbus_read_byte_data(dev, 0x4F))==0x01) || (dev < 0)) {
int i;
smbus_write_byte_data(dev, 0x03, MCU_DATA_PAGE);
for (i=0; i<16; i++) {
edid[j*16 + i] = smbus_read_byte_data(dev, es_map[i] );
}
smbus_write_byte_data(dev, 0x03, 0x00);
break;
}
gettimeofday(&tv, NULL);
if (timercmp(&tv, &tout, >)) {
fprintf(stderr, "Timeout waiting for MCU to return EDID\n");
return -1;
}
}
}
return 0;
}