i2c: designware: Tidy up PCI support

This is hacked into the driver at present. It seems better to have it as
a separate driver that uses the base driver. Create a new file and put
the X86 code into it.

Actually the Baytrail settings should really come from the device tree.

Note that 'has_max_speed' is added as well. This is currently always false
but since only Baytrail provides the config, it does not affect operation
for other devices.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Heiko Schocher <hs@denx.de>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
Simon Glass 2019-12-06 21:41:40 -07:00 committed by Bin Meng
parent d721001fd6
commit 457df2337f
4 changed files with 134 additions and 89 deletions

View file

@ -14,6 +14,9 @@ obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o
ifdef CONFIG_DM_PCI
obj-$(CONFIG_SYS_I2C_DW) += designware_i2c_pci.o
endif
obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o

View file

@ -13,34 +13,6 @@
#include <asm/io.h> #include <asm/io.h>
#include "designware_i2c.h" #include "designware_i2c.h"
struct dw_scl_sda_cfg {
u32 ss_hcnt;
u32 fs_hcnt;
u32 ss_lcnt;
u32 fs_lcnt;
u32 sda_hold;
};
#ifdef CONFIG_X86
/* BayTrail HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg byt_config = {
.ss_hcnt = 0x200,
.fs_hcnt = 0x55,
.ss_lcnt = 0x200,
.fs_lcnt = 0x99,
.sda_hold = 0x6,
};
#endif
struct dw_i2c {
struct i2c_regs *regs;
struct dw_scl_sda_cfg *scl_sda_cfg;
struct reset_ctl_bulk resets;
#if CONFIG_IS_ENABLED(CLK)
struct clk clk;
#endif
};
#ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED #ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable) static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
{ {
@ -90,7 +62,9 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
unsigned int ena; unsigned int ena;
int i2c_spd; int i2c_spd;
if (speed >= I2C_MAX_SPEED) /* Allow max speed if there is no config, or the config allows it */
if (speed >= I2C_MAX_SPEED &&
(!scl_sda_cfg || scl_sda_cfg->has_max_speed))
i2c_spd = IC_SPEED_MODE_MAX; i2c_spd = IC_SPEED_MODE_MAX;
else if (speed >= I2C_FAST_SPEED) else if (speed >= I2C_FAST_SPEED)
i2c_spd = IC_SPEED_MODE_FAST; i2c_spd = IC_SPEED_MODE_FAST;
@ -106,7 +80,6 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK)); cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK));
switch (i2c_spd) { switch (i2c_spd) {
#ifndef CONFIG_X86 /* No High-speed for BayTrail yet */
case IC_SPEED_MODE_MAX: case IC_SPEED_MODE_MAX:
cntl |= IC_CON_SPD_SS; cntl |= IC_CON_SPD_SS;
if (scl_sda_cfg) { if (scl_sda_cfg) {
@ -119,7 +92,6 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
writel(hcnt, &i2c_base->ic_hs_scl_hcnt); writel(hcnt, &i2c_base->ic_hs_scl_hcnt);
writel(lcnt, &i2c_base->ic_hs_scl_lcnt); writel(lcnt, &i2c_base->ic_hs_scl_lcnt);
break; break;
#endif
case IC_SPEED_MODE_STANDARD: case IC_SPEED_MODE_STANDARD:
cntl |= IC_CON_SPD_SS; cntl |= IC_CON_SPD_SS;
@ -565,25 +537,20 @@ static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
return ret; return ret;
} }
static int designware_i2c_probe(struct udevice *bus) static int designware_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct dw_i2c *priv = dev_get_priv(bus);
priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
return 0;
}
int designware_i2c_probe(struct udevice *bus)
{ {
struct dw_i2c *priv = dev_get_priv(bus); struct dw_i2c *priv = dev_get_priv(bus);
int ret; int ret;
if (device_is_on_pci_bus(bus)) {
#ifdef CONFIG_DM_PCI
/* Save base address from PCI BAR */
priv->regs = (struct i2c_regs *)
dm_pci_map_bar(bus, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
#ifdef CONFIG_X86
/* Use BayTrail specific timing values */
priv->scl_sda_cfg = &byt_config;
#endif
#endif
} else {
priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
}
ret = reset_get_bulk(bus, &priv->resets); ret = reset_get_bulk(bus, &priv->resets);
if (ret) if (ret)
dev_warn(bus, "Can't get reset: %d\n", ret); dev_warn(bus, "Can't get reset: %d\n", ret);
@ -606,7 +573,7 @@ static int designware_i2c_probe(struct udevice *bus)
return __dw_i2c_init(priv->regs, 0, 0); return __dw_i2c_init(priv->regs, 0, 0);
} }
static int designware_i2c_remove(struct udevice *dev) int designware_i2c_remove(struct udevice *dev)
{ {
struct dw_i2c *priv = dev_get_priv(dev); struct dw_i2c *priv = dev_get_priv(dev);
@ -618,30 +585,7 @@ static int designware_i2c_remove(struct udevice *dev)
return reset_release_bulk(&priv->resets); return reset_release_bulk(&priv->resets);
} }
static int designware_i2c_bind(struct udevice *dev) const struct dm_i2c_ops designware_i2c_ops = {
{
static int num_cards;
char name[20];
/* Create a unique device name for PCI type devices */
if (device_is_on_pci_bus(dev)) {
/*
* ToDo:
* Setting req_seq in the driver is probably not recommended.
* But without a DT alias the number is not configured. And
* using this driver is impossible for PCIe I2C devices.
* This can be removed, once a better (correct) way for this
* is found and implemented.
*/
dev->req_seq = num_cards;
sprintf(name, "i2c_designware#%u", num_cards++);
device_set_name(dev, name);
}
return 0;
}
static const struct dm_i2c_ops designware_i2c_ops = {
.xfer = designware_i2c_xfer, .xfer = designware_i2c_xfer,
.probe_chip = designware_i2c_probe_chip, .probe_chip = designware_i2c_probe_chip,
.set_bus_speed = designware_i2c_set_bus_speed, .set_bus_speed = designware_i2c_set_bus_speed,
@ -656,28 +600,12 @@ U_BOOT_DRIVER(i2c_designware) = {
.name = "i2c_designware", .name = "i2c_designware",
.id = UCLASS_I2C, .id = UCLASS_I2C,
.of_match = designware_i2c_ids, .of_match = designware_i2c_ids,
.bind = designware_i2c_bind, .ofdata_to_platdata = designware_i2c_ofdata_to_platdata,
.probe = designware_i2c_probe, .probe = designware_i2c_probe,
.priv_auto_alloc_size = sizeof(struct dw_i2c), .priv_auto_alloc_size = sizeof(struct dw_i2c),
.remove = designware_i2c_remove, .remove = designware_i2c_remove,
.flags = DM_FLAG_OS_PREPARE, .flags = DM_FLAG_OS_PREPARE,
.ops = &designware_i2c_ops, .ops = &designware_i2c_ops,
}; };
#ifdef CONFIG_X86
static struct pci_device_id designware_pci_supported[] = {
/* Intel BayTrail has 7 I2C controller located on the PCI bus */
{ PCI_VDEVICE(INTEL, 0x0f41) },
{ PCI_VDEVICE(INTEL, 0x0f42) },
{ PCI_VDEVICE(INTEL, 0x0f43) },
{ PCI_VDEVICE(INTEL, 0x0f44) },
{ PCI_VDEVICE(INTEL, 0x0f45) },
{ PCI_VDEVICE(INTEL, 0x0f46) },
{ PCI_VDEVICE(INTEL, 0x0f47) },
{},
};
U_BOOT_PCI_DEVICE(i2c_designware, designware_pci_supported);
#endif
#endif /* CONFIG_DM_I2C */ #endif /* CONFIG_DM_I2C */

View file

@ -7,6 +7,8 @@
#ifndef __DW_I2C_H_ #ifndef __DW_I2C_H_
#define __DW_I2C_H_ #define __DW_I2C_H_
#include <reset.h>
struct i2c_regs { struct i2c_regs {
u32 ic_con; /* 0x00 */ u32 ic_con; /* 0x00 */
u32 ic_tar; /* 0x04 */ u32 ic_tar; /* 0x04 */
@ -131,4 +133,37 @@ struct i2c_regs {
#define I2C_FAST_SPEED 400000 #define I2C_FAST_SPEED 400000
#define I2C_STANDARD_SPEED 100000 #define I2C_STANDARD_SPEED 100000
/**
* struct dw_scl_sda_cfg - I2C timing configuration
*
* @has_max_speed: Support maximum speed (1Mbps)
* @ss_hcnt: Standard speed high time in ns
* @fs_hcnt: Fast speed high time in ns
* @ss_lcnt: Standard speed low time in ns
* @fs_lcnt: Fast speed low time in ns
* @sda_hold: SDA hold time
*/
struct dw_scl_sda_cfg {
bool has_max_speed;
u32 ss_hcnt;
u32 fs_hcnt;
u32 ss_lcnt;
u32 fs_lcnt;
u32 sda_hold;
};
struct dw_i2c {
struct i2c_regs *regs;
struct dw_scl_sda_cfg *scl_sda_cfg;
struct reset_ctl_bulk resets;
#if CONFIG_IS_ENABLED(CLK)
struct clk clk;
#endif
};
extern const struct dm_i2c_ops designware_i2c_ops;
int designware_i2c_probe(struct udevice *bus);
int designware_i2c_remove(struct udevice *dev);
#endif /* __DW_I2C_H_ */ #endif /* __DW_I2C_H_ */

View file

@ -0,0 +1,79 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
* Copyright 2019 Google Inc
*/
#include <common.h>
#include <dm.h>
#include "designware_i2c.h"
/* BayTrail HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg byt_config = {
.ss_hcnt = 0x200,
.fs_hcnt = 0x55,
.ss_lcnt = 0x200,
.fs_lcnt = 0x99,
.sda_hold = 0x6,
};
static int designware_i2c_pci_probe(struct udevice *dev)
{
struct dw_i2c *priv = dev_get_priv(dev);
/* Save base address from PCI BAR */
priv->regs = (struct i2c_regs *)
dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
if (IS_ENABLED(CONFIG_INTEL_BAYTRAIL))
/* Use BayTrail specific timing values */
priv->scl_sda_cfg = &byt_config;
return designware_i2c_probe(dev);
}
static int designware_i2c_pci_bind(struct udevice *dev)
{
static int num_cards;
char name[20];
/*
* Create a unique device name for PCI type devices
* ToDo:
* Setting req_seq in the driver is probably not recommended.
* But without a DT alias the number is not configured. And
* using this driver is impossible for PCIe I2C devices.
* This can be removed, once a better (correct) way for this
* is found and implemented.
*/
dev->req_seq = num_cards;
sprintf(name, "i2c_designware#%u", num_cards++);
device_set_name(dev, name);
return 0;
}
U_BOOT_DRIVER(i2c_designware_pci) = {
.name = "i2c_designware_pci",
.id = UCLASS_I2C,
.bind = designware_i2c_pci_bind,
.probe = designware_i2c_pci_probe,
.priv_auto_alloc_size = sizeof(struct dw_i2c),
.remove = designware_i2c_remove,
.flags = DM_FLAG_OS_PREPARE,
.ops = &designware_i2c_ops,
};
static struct pci_device_id designware_pci_supported[] = {
/* Intel BayTrail has 7 I2C controller located on the PCI bus */
{ PCI_VDEVICE(INTEL, 0x0f41) },
{ PCI_VDEVICE(INTEL, 0x0f42) },
{ PCI_VDEVICE(INTEL, 0x0f43) },
{ PCI_VDEVICE(INTEL, 0x0f44) },
{ PCI_VDEVICE(INTEL, 0x0f45) },
{ PCI_VDEVICE(INTEL, 0x0f46) },
{ PCI_VDEVICE(INTEL, 0x0f47) },
{},
};
U_BOOT_PCI_DEVICE(i2c_designware_pci, designware_pci_supported);