soc/intel/common/lpss_i2c: simplify API and use common config structure
The apollolake and skylake had duplicate stanzas of code for initializing the i2c buses. Additionally, they also had very similar structures for providing settings for the i2c speed control. Introduce a new struct lpss_i2c_bus_config and utilize it in both apollolake and skylake thereby removing the need for SoC-specific structres. The new structure is used for initializing a bus fully as the lpss i2c API is simplified in that lpss_i2c_init() is only required to be called. The struct lpss_i2c_bus_config structure is passed in for both initializing and filling in the SSDT information. The formerly exposed functions are made static to reduce the external API exposure. BUG=chrome-os-partner:58889 Change-Id: Ib4fa8a7a4de052da75c778a7658741a5a8e0e6b9 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: https://review.coreboot.org/17348 Reviewed-by: Furquan Shaikh <furquan@google.com> Tested-by: build bot (Jenkins) Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
This commit is contained in:
parent
ed14a4e0df
commit
4668ba77ea
|
@ -28,15 +28,6 @@
|
|||
#define CLKREQ_DISABLED 0xf
|
||||
#define APOLLOLAKE_I2C_DEV_MAX 8
|
||||
|
||||
struct apollolake_i2c_config {
|
||||
/* Bus should be enabled prior to ramstage with temporary base */
|
||||
int early_init;
|
||||
/* Bus speed in Hz, default is I2C_SPEED_FAST (400 KHz) */
|
||||
enum i2c_speed speed;
|
||||
/* Specific bus speed configuration */
|
||||
struct lpss_i2c_speed_config speed_config[LPSS_I2C_SPEED_CONFIG_COUNT];
|
||||
};
|
||||
|
||||
/* Serial IRQ control. SERIRQ_QUIET is the default (0). */
|
||||
enum serirq_mode {
|
||||
SERIRQ_QUIET,
|
||||
|
@ -95,7 +86,7 @@ struct soc_intel_apollolake_config {
|
|||
enum serirq_mode serirq_mode;
|
||||
|
||||
/* I2C bus configuration */
|
||||
struct apollolake_i2c_config i2c[APOLLOLAKE_I2C_DEV_MAX];
|
||||
struct lpss_i2c_bus_config i2c[APOLLOLAKE_I2C_DEV_MAX];
|
||||
|
||||
uint8_t gpe0_dw1; /* GPE0_63_32 STS/EN */
|
||||
uint8_t gpe0_dw2; /* GPE0_95_64 STS/EN */
|
||||
|
|
|
@ -60,24 +60,12 @@ static int i2c_dev_to_bus(struct device *dev)
|
|||
static void i2c_dev_init(struct device *dev)
|
||||
{
|
||||
struct soc_intel_apollolake_config *config = dev->chip_info;
|
||||
const struct lpss_i2c_speed_config *sptr;
|
||||
enum i2c_speed speed;
|
||||
int i, bus = i2c_dev_to_bus(dev);
|
||||
int bus = i2c_dev_to_bus(dev);
|
||||
|
||||
if (!config || bus < 0)
|
||||
return;
|
||||
|
||||
speed = config->i2c[bus].speed ? : I2C_SPEED_FAST;
|
||||
lpss_i2c_init(bus, speed);
|
||||
|
||||
/* Apply custom speed config if it has been set by the board */
|
||||
for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) {
|
||||
sptr = &config->i2c[bus].speed_config[i];
|
||||
if (sptr->speed == speed) {
|
||||
lpss_i2c_set_speed_config(bus, sptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
lpss_i2c_init(bus, &config->i2c[bus]);
|
||||
}
|
||||
|
||||
static void i2c_fill_ssdt(struct device *dev)
|
||||
|
@ -89,7 +77,7 @@ static void i2c_fill_ssdt(struct device *dev)
|
|||
return;
|
||||
|
||||
acpigen_write_scope(acpi_device_path(dev));
|
||||
lpss_i2c_acpi_fill_ssdt(config->i2c[bus].speed_config);
|
||||
lpss_i2c_acpi_fill_ssdt(&config->i2c[bus]);
|
||||
acpigen_pop_len();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,6 @@ static int i2c_early_init_bus(unsigned bus)
|
|||
{
|
||||
ROMSTAGE_CONST struct soc_intel_apollolake_config *config;
|
||||
ROMSTAGE_CONST struct device *tree_dev;
|
||||
const struct lpss_i2c_speed_config *sptr;
|
||||
enum i2c_speed speed;
|
||||
pci_devfn_t dev;
|
||||
int devfn;
|
||||
uintptr_t base;
|
||||
|
@ -72,21 +70,11 @@ static int i2c_early_init_bus(unsigned bus)
|
|||
write32(reg, value);
|
||||
|
||||
/* Initialize the controller */
|
||||
speed = config->i2c[bus].speed ? : I2C_SPEED_FAST;
|
||||
if (lpss_i2c_init(bus, speed) < 0) {
|
||||
if (lpss_i2c_init(bus, &config->i2c[bus]) < 0) {
|
||||
printk(BIOS_ERR, "I2C%u failed to initialize\n", bus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Apply custom speed config if it has been set by the board */
|
||||
for (value = 0; value < LPSS_I2C_SPEED_CONFIG_COUNT; value++) {
|
||||
sptr = &config->i2c[bus].speed_config[value];
|
||||
if (sptr->speed == speed) {
|
||||
lpss_i2c_set_speed_config(bus, sptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -370,39 +370,8 @@ static void lpss_i2c_acpi_write_speed_config(
|
|||
acpigen_pop_len();
|
||||
}
|
||||
|
||||
void lpss_i2c_acpi_fill_ssdt(const struct lpss_i2c_speed_config *override)
|
||||
{
|
||||
const struct lpss_i2c_speed_config *sptr;
|
||||
struct lpss_i2c_speed_config sgen;
|
||||
enum i2c_speed speeds[LPSS_I2C_SPEED_CONFIG_COUNT] = {
|
||||
I2C_SPEED_STANDARD,
|
||||
I2C_SPEED_FAST,
|
||||
I2C_SPEED_FAST_PLUS,
|
||||
I2C_SPEED_HIGH,
|
||||
};
|
||||
int i;
|
||||
|
||||
/* Report timing values for the OS driver */
|
||||
for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) {
|
||||
/* Generate speed config for default case */
|
||||
if (lpss_i2c_gen_speed_config(speeds[i], &sgen) < 0)
|
||||
continue;
|
||||
|
||||
/* Apply board specific override for this speed if found */
|
||||
for (sptr = override; sptr && sptr->speed; sptr++) {
|
||||
if (sptr->speed == speeds[i]) {
|
||||
memcpy(&sgen, sptr, sizeof(sgen));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate ACPI based on selected speed config */
|
||||
lpss_i2c_acpi_write_speed_config(&sgen);
|
||||
}
|
||||
}
|
||||
|
||||
int lpss_i2c_set_speed_config(unsigned bus,
|
||||
const struct lpss_i2c_speed_config *config)
|
||||
static int lpss_i2c_set_speed_config(unsigned bus,
|
||||
const struct lpss_i2c_speed_config *config)
|
||||
{
|
||||
struct lpss_i2c_regs *regs;
|
||||
void *hcnt_reg, *lcnt_reg;
|
||||
|
@ -442,16 +411,26 @@ int lpss_i2c_set_speed_config(unsigned bus,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int lpss_i2c_gen_speed_config(enum i2c_speed speed,
|
||||
struct lpss_i2c_speed_config *config)
|
||||
static int lpss_i2c_gen_speed_config(enum i2c_speed speed,
|
||||
const struct lpss_i2c_bus_config *bcfg,
|
||||
struct lpss_i2c_speed_config *config)
|
||||
{
|
||||
const int ic_clk = CONFIG_SOC_INTEL_COMMON_LPSS_I2C_CLOCK_MHZ;
|
||||
uint16_t hcnt_min, lcnt_min;
|
||||
int i;
|
||||
|
||||
/* Clock must be provided by Kconfig */
|
||||
if (!ic_clk || !config)
|
||||
if (!ic_clk)
|
||||
return -1;
|
||||
|
||||
/* Apply board specific override for this speed if found */
|
||||
for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) {
|
||||
if (bcfg->speed_config[i].speed != speed)
|
||||
continue;
|
||||
memcpy(config, &bcfg->speed_config[i], sizeof(*config));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (speed >= I2C_SPEED_HIGH) {
|
||||
/* High speed */
|
||||
hcnt_min = MIN_HS_SCL_HIGHTIME;
|
||||
|
@ -478,7 +457,8 @@ int lpss_i2c_gen_speed_config(enum i2c_speed speed,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int lpss_i2c_set_speed(unsigned bus, enum i2c_speed speed)
|
||||
static int lpss_i2c_set_speed(unsigned bus, enum i2c_speed speed,
|
||||
const struct lpss_i2c_bus_config *bcfg)
|
||||
{
|
||||
struct lpss_i2c_regs *regs;
|
||||
struct lpss_i2c_speed_config config;
|
||||
|
@ -504,7 +484,7 @@ int lpss_i2c_set_speed(unsigned bus, enum i2c_speed speed)
|
|||
}
|
||||
|
||||
/* Generate speed config based on clock */
|
||||
if (lpss_i2c_gen_speed_config(speed, &config) < 0)
|
||||
if (lpss_i2c_gen_speed_config(speed, bcfg, &config) < 0)
|
||||
return -1;
|
||||
|
||||
/* Select this speed in the control register */
|
||||
|
@ -516,9 +496,40 @@ int lpss_i2c_set_speed(unsigned bus, enum i2c_speed speed)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int lpss_i2c_init(unsigned bus, enum i2c_speed speed)
|
||||
void lpss_i2c_acpi_fill_ssdt(const struct lpss_i2c_bus_config *bcfg)
|
||||
{
|
||||
struct lpss_i2c_speed_config sgen;
|
||||
enum i2c_speed speeds[LPSS_I2C_SPEED_CONFIG_COUNT] = {
|
||||
I2C_SPEED_STANDARD,
|
||||
I2C_SPEED_FAST,
|
||||
I2C_SPEED_FAST_PLUS,
|
||||
I2C_SPEED_HIGH,
|
||||
};
|
||||
int i;
|
||||
|
||||
if (!bcfg)
|
||||
return;
|
||||
|
||||
/* Report timing values for the OS driver */
|
||||
for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) {
|
||||
/* Generate speed config. */
|
||||
if (lpss_i2c_gen_speed_config(speeds[i], bcfg, &sgen) < 0)
|
||||
continue;
|
||||
|
||||
/* Generate ACPI based on selected speed config */
|
||||
lpss_i2c_acpi_write_speed_config(&sgen);
|
||||
}
|
||||
}
|
||||
|
||||
int lpss_i2c_init(unsigned bus, const struct lpss_i2c_bus_config *bcfg)
|
||||
{
|
||||
struct lpss_i2c_regs *regs;
|
||||
enum i2c_speed speed;
|
||||
|
||||
if (!bcfg)
|
||||
return -1;
|
||||
|
||||
speed = bcfg->speed ? : I2C_SPEED_FAST;
|
||||
|
||||
regs = (struct lpss_i2c_regs *)lpss_i2c_base_address(bus);
|
||||
if (!regs) {
|
||||
|
@ -536,7 +547,7 @@ int lpss_i2c_init(unsigned bus, enum i2c_speed speed)
|
|||
CONTROL_RESTART_ENABLE);
|
||||
|
||||
/* Set bus speed to FAST by default */
|
||||
if (lpss_i2c_set_speed(bus, speed ? : I2C_SPEED_FAST) < 0) {
|
||||
if (lpss_i2c_set_speed(bus, speed, bcfg) < 0) {
|
||||
printk(BIOS_ERR, "I2C failed to set speed for bus %u\n", bus);
|
||||
return -1;
|
||||
}
|
||||
|
@ -549,7 +560,7 @@ int lpss_i2c_init(unsigned bus, enum i2c_speed speed)
|
|||
write32(®s->intr_mask, INTR_STAT_STOP_DET);
|
||||
|
||||
printk(BIOS_INFO, "LPSS I2C bus %u at 0x%p (%u KHz)\n",
|
||||
bus, regs, (speed ? : I2C_SPEED_FAST) / KHz);
|
||||
bus, regs, speed / KHz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,15 @@ struct lpss_i2c_speed_config {
|
|||
*/
|
||||
#define LPSS_I2C_SPEED_CONFIG_COUNT 4
|
||||
|
||||
struct lpss_i2c_bus_config {
|
||||
/* Bus should be enabled prior to ramstage with temporary base */
|
||||
int early_init;
|
||||
/* Bus speed in Hz, default is I2C_SPEED_FAST (400 KHz) */
|
||||
enum i2c_speed speed;
|
||||
/* Specific bus speed configuration */
|
||||
struct lpss_i2c_speed_config speed_config[LPSS_I2C_SPEED_CONFIG_COUNT];
|
||||
};
|
||||
|
||||
#define LPSS_I2C_SPEED_CONFIG(speedval,lcnt,hcnt,hold) \
|
||||
{ \
|
||||
.speed = I2C_SPEED_ ## speedval, \
|
||||
|
@ -66,38 +75,11 @@ struct lpss_i2c_speed_config {
|
|||
*/
|
||||
uintptr_t lpss_i2c_base_address(unsigned bus);
|
||||
|
||||
/*
|
||||
* Generate speed configuration for requested controller and bus speed.
|
||||
*
|
||||
* This allows a SOC or board to automatically generate speed config to use
|
||||
* in firmware and provide to the OS.
|
||||
*/
|
||||
int lpss_i2c_gen_speed_config(enum i2c_speed speed,
|
||||
struct lpss_i2c_speed_config *config);
|
||||
|
||||
/*
|
||||
* Set raw speed configuration for given speed type.
|
||||
*
|
||||
* This allows a SOC or board to override the automatic bus speed calculation
|
||||
* and provided specific values for the driver to use.
|
||||
*/
|
||||
int lpss_i2c_set_speed_config(unsigned bus,
|
||||
const struct lpss_i2c_speed_config *config);
|
||||
|
||||
/*
|
||||
* Generate I2C timing information into the SSDT for the OS driver to consume,
|
||||
* optionally applying override values provided by the caller.
|
||||
*/
|
||||
void lpss_i2c_acpi_fill_ssdt(const struct lpss_i2c_speed_config *override);
|
||||
|
||||
/*
|
||||
* Set I2C bus speed for this controller.
|
||||
*
|
||||
* This allows an SOC or board to set the basic I2C bus speed. Values for the
|
||||
* controller configuration registers will be calculated, for more specific
|
||||
* control the raw configuration can be provided to lpss_i2c_set_speed_config().
|
||||
*/
|
||||
int lpss_i2c_set_speed(unsigned bus, enum i2c_speed speed);
|
||||
void lpss_i2c_acpi_fill_ssdt(const struct lpss_i2c_bus_config *bcfg);
|
||||
|
||||
/*
|
||||
* Initialize this bus controller and set the speed.
|
||||
|
@ -108,6 +90,6 @@ int lpss_i2c_set_speed(unsigned bus, enum i2c_speed speed);
|
|||
* The SOC *must* define CONFIG_SOC_INTEL_COMMON_LPSS_I2C_CLOCK for the
|
||||
* bus speed calculation to be correct.
|
||||
*/
|
||||
int lpss_i2c_init(unsigned bus, enum i2c_speed speed);
|
||||
int lpss_i2c_init(unsigned bus, const struct lpss_i2c_bus_config *bcfg);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -46,8 +46,6 @@ static void i2c_early_init_bus(unsigned bus)
|
|||
{
|
||||
ROMSTAGE_CONST struct soc_intel_skylake_config *config;
|
||||
ROMSTAGE_CONST struct device *tree_dev;
|
||||
const struct lpss_i2c_speed_config *sptr;
|
||||
enum i2c_speed speed;
|
||||
pci_devfn_t dev;
|
||||
int devfn;
|
||||
uintptr_t base;
|
||||
|
@ -86,17 +84,7 @@ static void i2c_early_init_bus(unsigned bus)
|
|||
write32(reg, value);
|
||||
|
||||
/* Initialize the controller */
|
||||
speed = config->i2c[bus].speed ? : I2C_SPEED_FAST;
|
||||
lpss_i2c_init(bus, speed);
|
||||
|
||||
/* Apply custom speed config if it has been set by the board */
|
||||
for (value = 0; value < LPSS_I2C_SPEED_CONFIG_COUNT; value++) {
|
||||
sptr = &config->i2c[bus].speed_config[value];
|
||||
if (sptr->speed == speed) {
|
||||
lpss_i2c_set_speed_config(bus, sptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
lpss_i2c_init(bus, &config->i2c[bus]);
|
||||
}
|
||||
|
||||
void i2c_early_init(void)
|
||||
|
|
|
@ -201,7 +201,7 @@ struct soc_intel_skylake_config {
|
|||
/* I2C */
|
||||
/* Bus voltage level, default is 3.3V */
|
||||
enum skylake_i2c_voltage i2c_voltage[SKYLAKE_I2C_DEV_MAX];
|
||||
struct skylake_i2c_config i2c[SKYLAKE_I2C_DEV_MAX];
|
||||
struct lpss_i2c_bus_config i2c[SKYLAKE_I2C_DEV_MAX];
|
||||
|
||||
/* Camera */
|
||||
u8 Cio2Enable;
|
||||
|
|
|
@ -56,24 +56,12 @@ static int i2c_dev_to_bus(struct device *dev)
|
|||
static void i2c_dev_init(struct device *dev)
|
||||
{
|
||||
struct soc_intel_skylake_config *config = dev->chip_info;
|
||||
const struct lpss_i2c_speed_config *sptr;
|
||||
enum i2c_speed speed;
|
||||
int i, bus = i2c_dev_to_bus(dev);
|
||||
int bus = i2c_dev_to_bus(dev);
|
||||
|
||||
if (!config || bus < 0)
|
||||
return;
|
||||
|
||||
speed = config->i2c[bus].speed ? : I2C_SPEED_FAST;
|
||||
lpss_i2c_init(bus, speed);
|
||||
|
||||
/* Apply custom speed config if it has been set by the board */
|
||||
for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) {
|
||||
sptr = &config->i2c[bus].speed_config[i];
|
||||
if (sptr->speed == speed) {
|
||||
lpss_i2c_set_speed_config(bus, sptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
lpss_i2c_init(bus, &config->i2c[bus]);
|
||||
}
|
||||
|
||||
/* Generate ACPI I2C device objects */
|
||||
|
@ -86,7 +74,7 @@ static void i2c_fill_ssdt(struct device *dev)
|
|||
return;
|
||||
|
||||
acpigen_write_scope(acpi_device_path(dev));
|
||||
lpss_i2c_acpi_fill_ssdt(config->i2c[bus].speed_config);
|
||||
lpss_i2c_acpi_fill_ssdt(&config->i2c[bus]);
|
||||
acpigen_pop_len();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue