video: configure HDMI from HPS.

This commit is contained in:
Sorgelig
2022-05-12 06:07:31 +08:00
parent 3341b03e2e
commit ec5577a620
6 changed files with 484 additions and 141 deletions

View File

@@ -78,6 +78,7 @@
<ClCompile Include="scaler.cpp" />
<ClCompile Include="scheduler.cpp" />
<ClCompile Include="shmem.cpp" />
<ClCompile Include="smbus.cpp" />
<ClCompile Include="spi.cpp" />
<ClCompile Include="support\arcade\buffer.cpp" />
<ClCompile Include="support\arcade\mra_loader.cpp" />
@@ -146,6 +147,7 @@
<ClInclude Include="scaler.h" />
<ClInclude Include="scheduler.h" />
<ClInclude Include="shmem.h" />
<ClInclude Include="smbus.h" />
<ClInclude Include="spi.h" />
<ClInclude Include="support.h" />
<ClInclude Include="support\arcade\buffer.h" />

View File

@@ -220,6 +220,9 @@
<ClCompile Include="support\uef\uef_reader.cpp">
<Filter>Source Files\support</Filter>
</ClCompile>
<ClCompile Include="smbus.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="battery.h">
@@ -426,5 +429,8 @@
<ClInclude Include="support\psx\mcdheader.h">
<Filter>Header Files\support</Filter>
</ClInclude>
<ClInclude Include="smbus.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -34,140 +34,22 @@
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#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;
}

262
smbus.cpp Normal file
View File

@@ -0,0 +1,262 @@
/*
smbus.c - SMBus level access helper functions
Copyright (C) 1995-1997 Simon G. Vogl
Copyright (C) 1998-1999 Frodo Looijaard <frodol@dds.nl>
Copyright (C) 2012-2013 Jean Delvare <jdelvare@suse.de>
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 <errno.h>
#include <stddef.h>
#include <unistd.h>
#include <linux/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#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);
}

23
smbus.h Normal file
View File

@@ -0,0 +1,23 @@
#include <stdint.h>
#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

187
video.cpp
View File

@@ -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;