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:
parent
6f6a10db5c
commit
7a714c74af
|
@ -203,6 +203,10 @@ class Builder:
|
|||
csr_base = self.soc.mem_regions['csr'].origin)
|
||||
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
|
||||
git_contents = export.get_git_header()
|
||||
write_to_file(os.path.join(self.generated_dir, "git.h"), git_contents)
|
||||
|
|
|
@ -272,6 +272,47 @@ def get_csr_header(regions, constants, csr_base=None, with_access_functions=True
|
|||
r += "\n#endif\n"
|
||||
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 --------------------------------------------------------------------------------------
|
||||
|
||||
def get_csr_json(csr_regions={}, constants={}, mem_regions={}):
|
||||
|
|
|
@ -174,6 +174,9 @@ class SoCCore(LiteXSoC):
|
|||
# Wishbone Slaves.
|
||||
self.wb_slaves = {}
|
||||
|
||||
# I2C initialisation tables
|
||||
self.i2c_init = []
|
||||
|
||||
# Modules instances ------------------------------------------------------------------------
|
||||
|
||||
# Add SoCController
|
||||
|
@ -269,6 +272,9 @@ class SoCCore(LiteXSoC):
|
|||
def add_csr_region(self, name, 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 ---------------------------------------------------------------------------------
|
||||
|
||||
def do_finalize(self):
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include <libbase/spiflash.h>
|
||||
#include <libbase/uart.h>
|
||||
#include <libbase/i2c.h>
|
||||
|
||||
#include <liblitedram/sdram.h>
|
||||
|
||||
|
@ -91,6 +92,10 @@ __attribute__((__used__)) int main(int i, char **c)
|
|||
uart_init();
|
||||
#endif
|
||||
|
||||
#ifdef CSR_I2C_BASE
|
||||
i2c_send_init_cmds();
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SIM_DISABLE_BIOS_PROMPT
|
||||
printf("\n");
|
||||
printf("\e[1m __ _ __ _ __\e[0m\n");
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
// 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 <stdio.h>
|
||||
|
||||
#include <generated/csr.h>
|
||||
#include <generated/i2c.h>
|
||||
|
||||
#ifdef CSR_I2C_BASE
|
||||
|
||||
#define I2C_PERIOD_CYCLES (CONFIG_CLOCK_FREQUENCY / I2C_FREQ_HZ)
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
i2c_w_write(
|
||||
current_i2c_write(
|
||||
((oe & 1) << CSR_I2C_W_OE_OFFSET) |
|
||||
((scl & 1) << CSR_I2C_W_SCL_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_DELAY(1);
|
||||
// read in the middle of SCL high
|
||||
value = i2c_r_read() & 1;
|
||||
value = current_i2c_read() & 1;
|
||||
I2C_DELAY(1);
|
||||
i2c_oe_scl_sda(0, 0, 0);
|
||||
I2C_DELAY(1);
|
||||
|
|
|
@ -6,6 +6,15 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#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 */
|
||||
#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_read(unsigned char slave_addr, unsigned char addr, unsigned char *data, unsigned int len, bool send_stop);
|
||||
bool i2c_poll(unsigned char slave_addr);
|
||||
int i2c_send_init_cmds(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue