From ec5577a620f7481eb13c3f0e7983d4be61f3e117 Mon Sep 17 00:00:00 2001 From: Sorgelig Date: Thu, 12 May 2022 06:07:31 +0800 Subject: [PATCH] video: configure HDMI from HPS. --- MiSTer.vcxproj | 2 + MiSTer.vcxproj.filters | 6 + battery.cpp | 145 +---------------------- smbus.cpp | 262 +++++++++++++++++++++++++++++++++++++++++ smbus.h | 23 ++++ video.cpp | 187 ++++++++++++++++++++++++++++- 6 files changed, 484 insertions(+), 141 deletions(-) create mode 100644 smbus.cpp create mode 100644 smbus.h 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;