i2c: automatic device init by the BIOS

The BIOS can now initialize I2C peripherals during the boot.
The add_i2c_init_table method of the soc speficy parameters:

self.submodules.i2c = I2CMaster(pads)
self.add_i2c_init_table("i2c", i2c_addr=0x4c, table=it6263_i2c_hdmi_tx)

it6263_i2c_hdmi_tx = [
  (0x05, 0x40),
  (0x04, 0x3D),
  (0x04, 0x1D)
  ...

The table is a list of tupple as (address, value).
This commit is contained in:
Franck Jullien 2022-02-01 21:22:40 +01:00
parent 6f6a10db5c
commit 7a714c74af
6 changed files with 113 additions and 2 deletions

View File

@ -203,6 +203,10 @@ class Builder:
csr_base = self.soc.mem_regions['csr'].origin) csr_base = self.soc.mem_regions['csr'].origin)
write_to_file(os.path.join(self.generated_dir, "csr.h"), csr_contents) write_to_file(os.path.join(self.generated_dir, "csr.h"), csr_contents)
# Generate I2C command/value table
i2c_contents = export.get_i2c_header(self.soc.i2c_init)
write_to_file(os.path.join(self.generated_dir, "i2c.h"), i2c_contents)
# Generate Git SHA1 of tools to git.h # Generate Git SHA1 of tools to git.h
git_contents = export.get_git_header() git_contents = export.get_git_header()
write_to_file(os.path.join(self.generated_dir, "git.h"), git_contents) write_to_file(os.path.join(self.generated_dir, "git.h"), git_contents)

View File

@ -272,6 +272,47 @@ def get_csr_header(regions, constants, csr_base=None, with_access_functions=True
r += "\n#endif\n" r += "\n#endif\n"
return r return r
def get_i2c_header(i2c_init_values):
r = generated_banner("//")
r += "#ifndef __GENERATED_I2C_H\n#define __GENERATED_I2C_H\n\n"
if i2c_init_values:
r += "#include <libbase/i2c.h>\n\n"
r += "struct i2c_cmds {\n"
r += "\tstruct i2c_ops ops;\n"
r += "\tuint32_t *init_table;\n"
r += "\tint nb_cmds;\n"
r += "\tint addr_len;\n"
r += "\tint i2c_addr;\n"
r += "};\n"
r += "\n#define I2C_INIT\n"
r += "#define I2C_INIT_DEVS {}\n\n".format(len(i2c_init_values))
for i, (dev, i2c_addr, table, _) in enumerate(i2c_init_values):
r += "uint32_t {}_{}_{}_init_table[{}] = {{\n".format(dev, hex(i2c_addr), i, len(table) * 2)
for addr, data in table:
r += "\t0x{:04X}, 0x{:02X},\n".format(addr, data)
r += "};\n"
r += "static struct i2c_cmds i2c_init[I2C_INIT_DEVS] = {\n"
for i, (dev, i2c_addr, table, addr_len) in enumerate(i2c_init_values):
r += "\t{\n"
r += "\t\t.ops.write = {}_w_write,\n".format(dev)
r += "\t\t.ops.read = {}_r_read,\n".format(dev)
r += "\t\t.init_table = {}_{}_{}_init_table,\n".format(dev, hex(i2c_addr), i)
r += "\t\t.nb_cmds = {},\n".format(len(table))
r += "\t\t.i2c_addr = {},\n".format(hex(i2c_addr))
r += "\t\t.addr_len = {},\n".format(addr_len)
r += "\t},\n"
r += "};\n"
else:
r += "\n// No initialization values\n"
r += "\n#endif\n"
return r
# JSON Export -------------------------------------------------------------------------------------- # JSON Export --------------------------------------------------------------------------------------
def get_csr_json(csr_regions={}, constants={}, mem_regions={}): def get_csr_json(csr_regions={}, constants={}, mem_regions={}):

View File

@ -174,6 +174,9 @@ class SoCCore(LiteXSoC):
# Wishbone Slaves. # Wishbone Slaves.
self.wb_slaves = {} self.wb_slaves = {}
# I2C initialisation tables
self.i2c_init = []
# Modules instances ------------------------------------------------------------------------ # Modules instances ------------------------------------------------------------------------
# Add SoCController # Add SoCController
@ -269,6 +272,9 @@ class SoCCore(LiteXSoC):
def add_csr_region(self, name, origin, busword, obj): def add_csr_region(self, name, origin, busword, obj):
self.csr_regions[name] = SoCCSRRegion(origin, busword, obj) self.csr_regions[name] = SoCCSRRegion(origin, busword, obj)
def add_i2c_init_table(self, dev, i2c_addr, table, addr_len=1):
self.i2c_init.append((dev, i2c_addr, table, addr_len))
# Finalization --------------------------------------------------------------------------------- # Finalization ---------------------------------------------------------------------------------
def do_finalize(self): def do_finalize(self):

View File

@ -36,6 +36,7 @@
#include <libbase/spiflash.h> #include <libbase/spiflash.h>
#include <libbase/uart.h> #include <libbase/uart.h>
#include <libbase/i2c.h>
#include <liblitedram/sdram.h> #include <liblitedram/sdram.h>
@ -91,6 +92,10 @@ __attribute__((__used__)) int main(int i, char **c)
uart_init(); uart_init();
#endif #endif
#ifdef CSR_I2C_BASE
i2c_send_init_cmds();
#endif
#ifndef CONFIG_SIM_DISABLE_BIOS_PROMPT #ifndef CONFIG_SIM_DISABLE_BIOS_PROMPT
printf("\n"); printf("\n");
printf("\e[1m __ _ __ _ __\e[0m\n"); printf("\e[1m __ _ __ _ __\e[0m\n");

View File

@ -1,13 +1,20 @@
// This file is Copyright (c) 2020 Antmicro <www.antmicro.com> // This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
// This file is Copyright (c) 2022 Franck Jullien <franck.jullien@collshade.fr>
#include "i2c.h" #include "i2c.h"
#include <stdio.h>
#include <generated/csr.h> #include <generated/csr.h>
#include <generated/i2c.h>
#ifdef CSR_I2C_BASE #ifdef CSR_I2C_BASE
#define I2C_PERIOD_CYCLES (CONFIG_CLOCK_FREQUENCY / I2C_FREQ_HZ) #define I2C_PERIOD_CYCLES (CONFIG_CLOCK_FREQUENCY / I2C_FREQ_HZ)
#define I2C_DELAY(n) cdelay((n)*I2C_PERIOD_CYCLES/4) #define I2C_DELAY(n) cdelay((n)*I2C_PERIOD_CYCLES/4)
i2c_write_t current_i2c_write = i2c_w_write;
i2c_read_t current_i2c_read = i2c_r_read;
static inline void cdelay(int i) static inline void cdelay(int i)
{ {
while(i > 0) { while(i > 0) {
@ -16,9 +23,47 @@ static inline void cdelay(int i)
} }
} }
int i2c_send_init_cmds(void)
{
#ifdef I2C_INIT
struct i2c_cmds *i2c_cmd;
int dev, i, len;
uint8_t data[2];
uint8_t addr;
for (dev = 0; dev < I2C_INIT_DEVS; dev++) {
i2c_cmd = &i2c_init[dev];
current_i2c_write = i2c_cmd->ops.write;
current_i2c_read = i2c_cmd->ops.read;
for (i = 0; i < i2c_cmd->nb_cmds; i++) {
if (i2c_cmd->addr_len == 2) {
len = 2;
addr = (i2c_cmd->init_table[i*2] >> 8) & 0xff;
data[0] = i2c_cmd->init_table[i*2] & 0xff;
data[1] = i2c_cmd->init_table[(i*2) + 1] & 0xff;
} else {
len = 1;
addr = i2c_cmd->init_table[i*2] & 0xff;
data[0] = i2c_cmd->init_table[(i*2) + 1] & 0xff;
}
if (!i2c_write(i2c_cmd->i2c_addr, addr, data, len))
printf("Error during i2c write at address 0x%04x\n", addr);
}
}
current_i2c_write = i2c_w_write;
current_i2c_read = i2c_r_read;
#endif
return 0;
}
static inline void i2c_oe_scl_sda(bool oe, bool scl, bool sda) static inline void i2c_oe_scl_sda(bool oe, bool scl, bool sda)
{ {
i2c_w_write( current_i2c_write(
((oe & 1) << CSR_I2C_W_OE_OFFSET) | ((oe & 1) << CSR_I2C_W_OE_OFFSET) |
((scl & 1) << CSR_I2C_W_SCL_OFFSET) | ((scl & 1) << CSR_I2C_W_SCL_OFFSET) |
((sda & 1) << CSR_I2C_W_SDA_OFFSET) ((sda & 1) << CSR_I2C_W_SDA_OFFSET)
@ -69,7 +114,7 @@ static int i2c_receive_bit(void)
i2c_oe_scl_sda(0, 1, 0); i2c_oe_scl_sda(0, 1, 0);
I2C_DELAY(1); I2C_DELAY(1);
// read in the middle of SCL high // read in the middle of SCL high
value = i2c_r_read() & 1; value = current_i2c_read() & 1;
I2C_DELAY(1); I2C_DELAY(1);
i2c_oe_scl_sda(0, 0, 0); i2c_oe_scl_sda(0, 0, 0);
I2C_DELAY(1); I2C_DELAY(1);

View File

@ -6,6 +6,15 @@ extern "C" {
#endif #endif
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
typedef void (*i2c_write_t)(uint32_t v);
typedef uint32_t (*i2c_read_t)(void);
struct i2c_ops {
i2c_write_t write;
i2c_read_t read;
};
/* I2C frequency defaults to a safe value in range 10-100 kHz to be compatible with SMBus */ /* I2C frequency defaults to a safe value in range 10-100 kHz to be compatible with SMBus */
#ifndef I2C_FREQ_HZ #ifndef I2C_FREQ_HZ
@ -19,6 +28,7 @@ void i2c_reset(void);
bool i2c_write(unsigned char slave_addr, unsigned char addr, const unsigned char *data, unsigned int len); bool i2c_write(unsigned char slave_addr, unsigned char addr, const unsigned char *data, unsigned int len);
bool i2c_read(unsigned char slave_addr, unsigned char addr, unsigned char *data, unsigned int len, bool send_stop); bool i2c_read(unsigned char slave_addr, unsigned char addr, unsigned char *data, unsigned int len, bool send_stop);
bool i2c_poll(unsigned char slave_addr); bool i2c_poll(unsigned char slave_addr);
int i2c_send_init_cmds(void);
#ifdef __cplusplus #ifdef __cplusplus
} }