diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj
index 1f438b6..74b14cc 100644
--- a/MiSTer.vcxproj
+++ b/MiSTer.vcxproj
@@ -78,6 +78,7 @@
+
@@ -146,6 +147,7 @@
+
diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters
index 75b5bbf..c3e2751 100644
--- a/MiSTer.vcxproj.filters
+++ b/MiSTer.vcxproj.filters
@@ -220,6 +220,9 @@
Source Files\support
+
+ Source Files
+
@@ -426,5 +429,8 @@
Header Files\support
+
+ Header Files
+
\ No newline at end of file
diff --git a/battery.cpp b/battery.cpp
index 3a4d7ef..29434fd 100644
--- a/battery.cpp
+++ b/battery.cpp
@@ -34,140 +34,22 @@
#include
#include
#include
+#include "smbus.h"
#include "battery.h"
#define MAX_COUNT 20 // Maximum number of trials
#define SLEEP_TIME 500 // time between two i2cget in microsec
-///////////////////////////////////////////////////////////////////////
-// I2C definitions
-
-#define I2C_SLAVE 0x0703
-#define I2C_SMBUS 0x0720 /* SMBus-level access */
-
-#define I2C_SMBUS_READ 1
-#define I2C_SMBUS_WRITE 0
-
-// SMBus transaction types
-
-#define I2C_SMBUS_QUICK 0
-#define I2C_SMBUS_BYTE 1
-#define I2C_SMBUS_BYTE_DATA 2
-#define I2C_SMBUS_WORD_DATA 3
-#define I2C_SMBUS_PROC_CALL 4
-#define I2C_SMBUS_BLOCK_DATA 5
-#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
-#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
-#define I2C_SMBUS_I2C_BLOCK_DATA 8
-
-// SMBus messages
-
-#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
-#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */
-
-// Structures used in the ioctl() calls
-
-union i2c_smbus_data
-{
- uint8_t byte;
- int8_t sbyte;
- uint16_t word;
- int16_t sword;
- uint8_t block [I2C_SMBUS_BLOCK_MAX + 2]; // block [0] is used for length + one more for PEC
-};
-
-struct i2c_smbus_ioctl_data
-{
- char read_write;
- uint8_t command;
- int size;
- union i2c_smbus_data *data;
-};
-
-static int i2c_smbus_access (int fd, char rw, uint8_t command, int size, union i2c_smbus_data *data)
-{
- struct i2c_smbus_ioctl_data args;
-
- args.read_write = rw;
- args.command = command;
- args.size = size;
- args.data = data;
- return ioctl (fd, I2C_SMBUS, &args);
-}
-
-static int i2c_smbus_write_quick(int fd, uint8_t value)
-{
- return i2c_smbus_access(fd, value, 0, I2C_SMBUS_QUICK, NULL);
-}
-
-///////////////////////////////////////////////////////////////////////
-
static int i2c_handle = -1;
-static int smbus_open(int dev_address)
-{
- // re-entry compatible
- if(i2c_handle < 0)
- {
- char str[16];
- for (int bus = 2; bus >= 0; bus--)
- {
- int fd;
- sprintf(str, "/dev/i2c-%d", bus);
-
- if ((fd = open(str, O_RDWR | O_CLOEXEC)) < 0)
- {
- printf("Unable to open I2C bus %s: %s\n", str, strerror(errno));
- continue;
- }
-
- if (ioctl(fd, I2C_SLAVE, dev_address) < 0)
- {
- printf("Unable to select I2C device on bus %s: %s\n", str, strerror(errno));
- close(fd);
- continue;
- }
-
- if (i2c_smbus_write_quick(fd, I2C_SMBUS_WRITE) < 0)
- {
- printf("Unable to detect SMBUS device on bus %s: %s\n", str, strerror(errno));
- close(fd);
- continue;
- }
-
- i2c_handle = fd;
- return 1;
- }
- return 0;
- }
- return 1;
-}
-
-/*
-static void smbus_close()
-{
- if(i2c_handle > 0) close(i2c_handle);
- i2c_handle = -1;
-}
-*/
-
-static int smbus_get(int address, short *data)
-{
- union i2c_smbus_data smbus_data;
-
- if (i2c_smbus_access (i2c_handle, I2C_SMBUS_READ, address, I2C_SMBUS_WORD_DATA, &smbus_data)) return 0;
-
- *data = smbus_data.sword;
- return 1;
-}
-
static int getReg(int reg, int min, int max)
{
int count = 0;
short value = -1;
while ((value == -1) && (count++ < MAX_COUNT))
{
- if (smbus_get(reg, &value))
+ value = i2c_smbus_read_word_data(i2c_handle, reg);
+ if (value >= 0)
{
if ((value > max) || (value < min)) value = -1; // out of limits
}
@@ -179,22 +61,11 @@ static int getReg(int reg, int min, int max)
int getBattery(int quick, struct battery_data_t *data)
{
- /*
- data->capacity = 80;
- data->load_current = -520;
- data->time = 312;
- data->current = 2510;
- data->voltage = 16200;
- data->cell[0] = 4101;
- data->cell[1] = 4102;
- data->cell[2] = 4103;
- data->cell[3] = 4104;
- return 1;
- */
// don't try to check if no battery device is present
if (i2c_handle == -2) return 0;
- if (!smbus_open(0x0b))
+ i2c_handle = i2c_open(0x0B, 1);
+ if (i2c_handle < 0)
{
printf("No battery found.\n");
i2c_handle = -2;
@@ -211,12 +82,6 @@ int getBattery(int quick, struct battery_data_t *data)
data->current = getReg(0x0F, 0, 5000);
data->voltage = getReg(0x09, 5000, 20000);
- /*
- data->cell[0] = getReg(0x3F, 1000, 5000);
- data->cell[1] = getReg(0x3E, 1000, 5000);
- data->cell[2] = getReg(0x3D, 1000, 5000);
- data->cell[3] = getReg(0x3C, 1000, 5000);
- */
return 1;
}
diff --git a/smbus.cpp b/smbus.cpp
new file mode 100644
index 0000000..2e524e6
--- /dev/null
+++ b/smbus.cpp
@@ -0,0 +1,262 @@
+/*
+ smbus.c - SMBus level access helper functions
+
+ Copyright (C) 1995-1997 Simon G. Vogl
+ Copyright (C) 1998-1999 Frodo Looijaard
+ Copyright (C) 2012-2013 Jean Delvare
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "smbus.h"
+
+#define I2C_SLAVE 0x0703
+#define I2C_SMBUS 0x0720 /* SMBus-level access */
+
+#define I2C_SMBUS_READ 1
+#define I2C_SMBUS_WRITE 0
+
+// SMBus transaction types
+#define I2C_SMBUS_QUICK 0
+#define I2C_SMBUS_BYTE 1
+#define I2C_SMBUS_BYTE_DATA 2
+#define I2C_SMBUS_WORD_DATA 3
+#define I2C_SMBUS_PROC_CALL 4
+#define I2C_SMBUS_BLOCK_DATA 5
+#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
+#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
+#define I2C_SMBUS_I2C_BLOCK_DATA 8
+
+// SMBus messages
+#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
+
+union i2c_smbus_data
+{
+ uint8_t byte;
+ uint16_t word;
+ uint8_t block[I2C_SMBUS_BLOCK_MAX + 2]; // block [0] is used for length + one more for PEC
+};
+
+struct i2c_smbus_ioctl_data
+{
+ uint8_t read_write;
+ uint8_t command;
+ uint32_t size;
+ union i2c_smbus_data *data;
+};
+
+static int i2c_smbus_access(int file, char read_write, uint8_t command,
+ int size, union i2c_smbus_data *data)
+{
+ struct i2c_smbus_ioctl_data args;
+ int err;
+
+ args.read_write = read_write;
+ args.command = command;
+ args.size = size;
+ args.data = data;
+
+ err = ioctl(file, I2C_SMBUS, &args);
+ if (err == -1) err = -errno;
+ return err;
+}
+
+int i2c_smbus_write_quick(int file, uint8_t value)
+{
+ return i2c_smbus_access(file, value, 0, I2C_SMBUS_QUICK, NULL);
+}
+
+int i2c_smbus_read_byte(int file)
+{
+ union i2c_smbus_data data;
+ int err;
+
+ err = i2c_smbus_access(file, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
+ if (err < 0) return err;
+
+ return 0x0FF & data.byte;
+}
+
+int i2c_smbus_write_byte(int file, uint8_t value)
+{
+ return i2c_smbus_access(file, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
+}
+
+int i2c_smbus_read_byte_data(int file, uint8_t command)
+{
+ union i2c_smbus_data data;
+ int err;
+
+ err = i2c_smbus_access(file, I2C_SMBUS_READ, command, I2C_SMBUS_BYTE_DATA, &data);
+ if (err < 0) return err;
+
+ return 0x0FF & data.byte;
+}
+
+int i2c_smbus_write_byte_data(int file, uint8_t command, uint8_t value)
+{
+ printf("i2c: %02X %02X\n", command, value);
+ union i2c_smbus_data data;
+ data.byte = value;
+ return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, I2C_SMBUS_BYTE_DATA, &data);
+}
+
+int i2c_smbus_read_word_data(int file, uint8_t command)
+{
+ union i2c_smbus_data data;
+ int err;
+
+ err = i2c_smbus_access(file, I2C_SMBUS_READ, command, I2C_SMBUS_WORD_DATA, &data);
+ if (err < 0) return err;
+
+ return 0x0FFFF & data.word;
+}
+
+int i2c_smbus_write_word_data(int file, uint8_t command, uint16_t value)
+{
+ union i2c_smbus_data data;
+ data.word = value;
+ return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, I2C_SMBUS_WORD_DATA, &data);
+}
+
+int i2c_smbus_process_call(int file, uint8_t command, uint16_t value)
+{
+ union i2c_smbus_data data;
+ data.word = value;
+ if (i2c_smbus_access(file, I2C_SMBUS_WRITE, command, I2C_SMBUS_PROC_CALL, &data)) return -1;
+ else return 0x0FFFF & data.word;
+}
+
+/* Returns the number of read bytes */
+int i2c_smbus_read_block_data(int file, uint8_t command, uint8_t *values)
+{
+ union i2c_smbus_data data;
+ int i, err;
+
+ err = i2c_smbus_access(file, I2C_SMBUS_READ, command, I2C_SMBUS_BLOCK_DATA, &data);
+ if (err < 0) return err;
+
+ for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i];
+ return data.block[0];
+}
+
+int i2c_smbus_write_block_data(int file, uint8_t command, uint8_t length, const uint8_t *values)
+{
+ union i2c_smbus_data data;
+ int i;
+ if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX;
+ for (i = 1; i <= length; i++) data.block[i] = values[i-1];
+ data.block[0] = length;
+ return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, I2C_SMBUS_BLOCK_DATA, &data);
+}
+
+/* Returns the number of read bytes */
+/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
+ ask for less than 32 bytes, your code will only work with kernels
+ 2.6.23 and later. */
+int i2c_smbus_read_i2c_block_data(int file, uint8_t command, uint8_t length, uint8_t *values)
+{
+ union i2c_smbus_data data;
+ int i, err;
+
+ if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX;
+ data.block[0] = length;
+
+ err = i2c_smbus_access(file, I2C_SMBUS_READ, command, length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : I2C_SMBUS_I2C_BLOCK_DATA, &data);
+ if (err < 0) return err;
+
+ for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i];
+ return data.block[0];
+}
+
+int i2c_smbus_write_i2c_block_data(int file, uint8_t command, uint8_t length, const uint8_t *values)
+{
+ union i2c_smbus_data data;
+ int i;
+ if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX;
+ for (i = 1; i <= length; i++) data.block[i] = values[i-1];
+ data.block[0] = length;
+ return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
+}
+
+/* Returns the number of read bytes */
+int i2c_smbus_block_process_call(int file, uint8_t command, uint8_t length, uint8_t *values)
+{
+ union i2c_smbus_data data;
+ int i, err;
+
+ if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX;
+ for (i = 1; i <= length; i++) data.block[i] = values[i-1];
+ data.block[0] = length;
+
+ err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command, I2C_SMBUS_BLOCK_PROC_CALL, &data);
+ if (err < 0) return err;
+
+ for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i];
+ return data.block[0];
+}
+
+int i2c_open(int dev_address, int is_smbus)
+{
+ char str[16];
+ for (int bus = 0; bus < 3; bus++)
+ {
+ int fd;
+ sprintf(str, "/dev/i2c-%d", bus);
+
+ if ((fd = open(str, O_RDWR | O_CLOEXEC)) < 0)
+ {
+ //printf("Unable to open I2C bus %s: %s\n", str, strerror(errno));
+ continue;
+ }
+
+ if (ioctl(fd, I2C_SLAVE, dev_address) < 0)
+ {
+ //printf("Unable to select I2C device 0x%X on bus %s: %s\n", dev_address, str, strerror(errno));
+ close(fd);
+ continue;
+ }
+
+ if (is_smbus)
+ {
+ if (i2c_smbus_write_quick(fd, 0) < 0)
+ {
+ //printf("Unable to detect SMBUS device on bus %s: %s\n", str, strerror(errno));
+ close(fd);
+ continue;
+ }
+ }
+ else
+ {
+ if (i2c_smbus_read_byte(fd) < 0)
+ {
+ //printf("Unable to detect I2C device on bus %s: %s\n", str, strerror(errno));
+ close(fd);
+ continue;
+ }
+ }
+
+ printf("Opened %s for device 0x%X\n", str, dev_address);
+ return fd;
+ }
+
+ return -1;
+}
+
+void i2c_close(int fd)
+{
+ if (fd >= 0) close(fd);
+}
diff --git a/smbus.h b/smbus.h
new file mode 100644
index 0000000..cd1ec1f
--- /dev/null
+++ b/smbus.h
@@ -0,0 +1,23 @@
+#include
+
+#ifndef SMBUS_H
+#define SMBUS_H
+
+int i2c_open(int dev_address, int is_smbus);
+void i2c_close(int fd);
+
+int i2c_smbus_write_quick(int file, uint8_t value);
+int i2c_smbus_read_byte(int file);
+int i2c_smbus_write_byte(int file, uint8_t value);
+int i2c_smbus_read_byte_data(int file, uint8_t command);
+int i2c_smbus_write_byte_data(int file, uint8_t command, uint8_t value);
+int i2c_smbus_read_word_data(int file, uint8_t command);
+int i2c_smbus_write_word_data(int file, uint8_t command, uint16_t value);
+int i2c_smbus_process_call(int file, uint8_t command, uint16_t value);
+int i2c_smbus_read_block_data(int file, uint8_t command, uint8_t *values);
+int i2c_smbus_write_block_data(int file, uint8_t command, uint8_t length, const uint8_t *values);
+int i2c_smbus_read_i2c_block_data(int file, uint8_t command, uint8_t length, uint8_t *values);
+int i2c_smbus_write_i2c_block_data(int file, uint8_t command, uint8_t length, const uint8_t *values);
+int i2c_smbus_block_process_call(int file, uint8_t command, uint8_t length, uint8_t *values);
+
+#endif
diff --git a/video.cpp b/video.cpp
index 3f8d500..c16f342 100644
--- a/video.cpp
+++ b/video.cpp
@@ -20,6 +20,7 @@
#include "video.h"
#include "input.h"
#include "shmem.h"
+#include "smbus.h"
#include "support.h"
#include "lib/imlib2/Imlib2.h"
@@ -883,6 +884,188 @@ void video_loadPreset(char *name)
}
}
+static void hdmi_config()
+{
+ int ypbpr = cfg.ypbpr && cfg.direct_video;
+
+ // address, value
+ uint8_t init_data[] = {
+ 0x98, 03, // ADI required Write.
+
+ 0xD6, 0b11000000, // [7:6] HPD Control...
+ // 00 = HPD is from both HPD pin or CDC HPD
+ // 01 = HPD is from CDC HPD
+ // 10 = HPD is from HPD pin
+ // 11 = HPD is always high
+
+ 0x41, 0x10, // Power Down control
+ 0x9A, 0x70, // ADI required Write.
+ 0x9C, 0x30, // ADI required Write.
+ 0x9D, 0b01100001, // [7:4] must be b0110!.
+ // [3:2] b00 = Input clock not divided. b01 = Clk divided by 2. b10 = Clk divided by 4. b11 = invalid!
+ // [1:0] must be b01!
+ 0xA2, 0xA4, // ADI required Write.
+ 0xA3, 0xA4, // ADI required Write.
+ 0xE0, 0xD0, // ADI required Write.
+
+
+ 0x35, 0x40,
+ 0x36, 0xD9,
+ 0x37, 0x0A,
+ 0x38, 0x00,
+ 0x39, 0x2D,
+ 0x3A, 0x00,
+
+ 0x16, 0b00111000, // Output Format 444 [7]=0.
+ // [6] must be 0!
+ // Colour Depth for Input Video data [5:4] b11 = 8-bit.
+ // Input Style [3:2] b10 = Style 1 (ignored when using 444 input).
+ // DDR Input Edge falling [1]=0 (not using DDR atm).
+ // Output Colour Space RGB [0]=0.
+
+ 0x17, 0b01100010, // Aspect ratio 16:9 [1]=1, 4:3 [1]=0
+
+ 0x18, (uint8_t)(ypbpr ? 0x86 : (cfg.hdmi_limited & 1) ? 0x8D : (cfg.hdmi_limited & 2) ? 0x8E : 0x00), // CSC Scaling Factors and Coefficients for RGB Full->Limited.
+ 0x19, (uint8_t)(ypbpr ? 0xDF : (cfg.hdmi_limited & 1) ? 0xBC : 0xFE), // Taken from table in ADV7513 Programming Guide.
+ 0x1A, (uint8_t)(ypbpr ? 0x1A : 0x00), // CSC Channel A.
+ 0x1B, (uint8_t)(ypbpr ? 0x3F : 0x00),
+ 0x1C, (uint8_t)(ypbpr ? 0x1E : 0x00),
+ 0x1D, (uint8_t)(ypbpr ? 0xE2 : 0x00),
+ 0x1E, (uint8_t)(ypbpr ? 0x07 : 0x01),
+ 0x1F, (uint8_t)(ypbpr ? 0xE7 : 0x00),
+
+ 0x20, (uint8_t)(ypbpr ? 0x04 : 0x00), // CSC Channel B.
+ 0x21, (uint8_t)(ypbpr ? 0x1C : 0x00),
+ 0x22, (uint8_t)(ypbpr ? 0x08 : (cfg.hdmi_limited & 1) ? 0x0D : 0x0E),
+ 0x23, (uint8_t)(ypbpr ? 0x11 : (cfg.hdmi_limited & 1) ? 0xBC : 0xFE),
+ 0x24, (uint8_t)(ypbpr ? 0x01 : 0x00),
+ 0x25, (uint8_t)(ypbpr ? 0x91 : 0x00),
+ 0x26, (uint8_t)(ypbpr ? 0x01 : 0x01),
+ 0x27, 0x00,
+
+ 0x28, (uint8_t)(ypbpr ? 0x1D : 0x00), // CSC Channel C.
+ 0x29, (uint8_t)(ypbpr ? 0xAE : 0x00),
+ 0x2A, (uint8_t)(ypbpr ? 0x1B : 0x00),
+ 0x2B, (uint8_t)(ypbpr ? 0x73 : 0x00),
+ 0x2C, (uint8_t)(ypbpr ? 0x06 : (cfg.hdmi_limited & 1) ? 0x0D : 0x0E),
+ 0x2D, (uint8_t)(ypbpr ? 0xDF : (cfg.hdmi_limited & 1) ? 0xBC : 0xFE),
+ 0x2E, (uint8_t)(ypbpr ? 0x07 : 0x01),
+ 0x2F, (uint8_t)(ypbpr ? 0xE7 : 0x00),
+
+ 0x3B, 0b01000000, // Pixel repetition [6:5] b00 AUTO. [4:3] b00 x1 mult of input clock. [2:1] b00 x1 pixel rep to send to HDMI Rx.
+ // Pixel repetition set to manual to avoid VIC auto detection as defined in ADV7513 Programming Guide
+
+ 0x40, 0x00, // General Control Packet Enable
+
+ 0x48, 0b00001000, // [6]=0 Normal bus order!
+ // [5] DDR Alignment.
+ // [4:3] b01 Data right justified (for YCbCr 422 input modes).
+
+ 0x49, 0xA8, // ADI required Write.
+ 0x4C, 0x00, // ADI required Write.
+
+ 0x55, 0b00010010, // [7] must be 0!. Set RGB444 in AVinfo Frame [6:5], Set active format [4].
+ // AVI InfoFrame Valid [4].
+ // Bar Info [3:2] b00 Bars invalid. b01 Bars vertical. b10 Bars horizontal. b11 Bars both.
+ // Scan Info [1:0] b00 (No data). b01 TV. b10 PC. b11 None.
+
+ 0x56, 0b00001000, // [5:4] Picture Aspect Ratio
+ // [3:0] Active Portion Aspect Ratio b1000 = Same as Picture Aspect Ratio
+
+ 0x57, (uint8_t)(0b10000000 // [7] IT Content. 0 - No. 1 - Yes (type set in register 0x59).
+ // [6:4] Color space (ignored for RGB)
+ | ((ypbpr || cfg.hdmi_limited) ? 0b0100 : 0b1000)), // [3:2] RGB Quantization range
+ // [1:0] Non-Uniform Scaled: 00 - None. 01 - Horiz. 10 - Vert. 11 - Both.
+
+ 0x3C, 0b00000000, // VIC b0000_0000 = VIC Unavailable
+
+ 0x59, (uint8_t)(((ypbpr || cfg.hdmi_limited) ? 0x00 : 0x40) // [7:6] [YQ1 YQ0] YCC Quantization Range: b00 = Limited Range, b01 = Full Range
+ | 0x30), // [5:4] IT Content Type b11 = Game
+ // [3:0] Pixel Repetition Fields b0000 = No Repetition
+
+ 0x73, 0x01,
+
+ 0x94, 0b10000000, // [7]=1 HPD Interrupt ENabled.
+
+ 0x99, 0x02, // ADI required Write.
+ 0x9B, 0x18, // ADI required Write.
+
+ 0x9F, 0x00, // ADI required Write.
+
+ 0xA1, 0b00000000, // [6]=1 Monitor Sense Power Down DISabled.
+
+ 0xA4, 0x08, // ADI required Write.
+ 0xA5, 0x04, // ADI required Write.
+ 0xA6, 0x00, // ADI required Write.
+ 0xA7, 0x00, // ADI required Write.
+ 0xA8, 0x00, // ADI required Write.
+ 0xA9, 0x00, // ADI required Write.
+ 0xAA, 0x00, // ADI required Write.
+ 0xAB, 0x40, // ADI required Write.
+
+ 0xAF, (uint8_t)(0b00000100 // [7]=0 HDCP Disabled.
+ // [6:5] must be b00!
+ // [4]=0 Current frame is unencrypted
+ // [3:2] must be b01!
+ | (cfg.dvi ? 0b00 : 0b10)), // [1]=1 HDMI Mode.
+ // [0] must be b0!
+
+ 0xB9, 0x00, // ADI required Write.
+
+ 0xBA, 0b01100000, // [7:5] Input Clock delay...
+ // b000 = -1.2ns.
+ // b001 = -0.8ns.
+ // b010 = -0.4ns.
+ // b011 = No delay.
+ // b100 = 0.4ns.
+ // b101 = 0.8ns.
+ // b110 = 1.2ns.
+ // b111 = 1.6ns.
+
+ 0xBB, 0x00, // ADI required Write.
+
+ 0xDE, 0x9C, // ADI required Write.
+ 0xE4, 0x60, // ADI required Write.
+ 0xFA, 0x7D, // Nbr of times to search for good phase
+
+ // (Audio stuff on Programming Guide, Page 66)...
+ 0x0A, 0b00000000, // [6:4] Audio Select. b000 = I2S.
+ // [3:2] Audio Mode. (HBR stuff, leave at 00!).
+
+ 0x0B, 0b00001110, //
+
+ 0x0C, 0b00000100, // [7] 0 = Use sampling rate from I2S stream. 1 = Use samp rate from I2C Register.
+ // [6] 0 = Use Channel Status bits from stream. 1 = Use Channel Status bits from I2C register.
+ // [2] 1 = I2S0 Enable.
+ // [1:0] I2S Format: 00 = Standard. 01 = Right Justified. 10 = Left Justified. 11 = AES.
+
+ 0x0D, 0b00010000, // [4:0] I2S Bit (Word) Width for Right-Justified.
+ 0x14, 0b00000010, // [3:0] Audio Word Length. b0010 = 16 bits.
+ 0x15, (uint8_t)((cfg.hdmi_audio_96k ? 0x80 : 0x00) | 0b0100000), // I2S Sampling Rate [7:4]. b0000 = (44.1KHz). b0010 = 48KHz.
+ // Input ID [3:1] b000 (0) = 24-bit RGB 444 or YCrCb 444 with Separate Syncs.
+
+ // Audio Clock Config
+ 0x01, 0x00, //
+ 0x02, (uint8_t)(cfg.hdmi_audio_96k ? 0x30 : 0x18), // Set N Value 12288/6144
+ 0x03, 0x00, //
+
+ 0x07, 0x01, //
+ 0x08, 0x22, // Set CTS Value 74250
+ 0x09, 0x0A, //
+ };
+
+ int fd = i2c_open(0x39, 0);
+ if (fd >= 0)
+ {
+ for (uint i = 0; i < sizeof(init_data); i += 2)
+ {
+ int res = i2c_smbus_write_byte_data(fd, init_data[i], init_data[i + 1]);
+ if (res < 0) printf("i2c: write error %d\n", res);
+ }
+ i2c_close(fd);
+ }
+}
+
static char fb_reset_cmd[128] = {};
static void set_video(vmode_custom_t *v, double Fpix)
{
@@ -928,7 +1111,7 @@ static void set_video(vmode_custom_t *v, double Fpix)
for (int i = 9; i < 21; i++)
{
printf("0x%X, ", v_cur.item[i]);
- if (i & 1) spi_w(v_cur.item[i] | ((i == 9 && Fpix && cfg.vsync_adjust == 2 && !is_menu()) ? 0x8000 : 0));
+ if (i & 1) spi_w(v_cur.item[i] | ((i == 9 && Fpix && cfg.vsync_adjust == 2 && !is_menu()) ? 0x8000 : 0) | 0x4000);
else
{
spi_w(v_cur.item[i]);
@@ -939,6 +1122,8 @@ static void set_video(vmode_custom_t *v, double Fpix)
printf("Fpix=%f\n", v_cur.Fpix);
DisableIO();
+ hdmi_config();
+
if (cfg.fb_size <= 1) cfg.fb_size = ((v_cur.item[1] * v_cur.item[5]) <= FB_SIZE) ? 1 : 2;
else if (cfg.fb_size == 3) cfg.fb_size = 2;
else if (cfg.fb_size > 4) cfg.fb_size = 4;