From 457df2337fc90431dc60b9b256ac1fdb8809f4cf Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Dec 2019 21:41:40 -0700 Subject: [PATCH] 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 Reviewed-by: Heiko Schocher Reviewed-by: Bin Meng --- drivers/i2c/Makefile | 3 + drivers/i2c/designware_i2c.c | 106 +++++-------------------------- drivers/i2c/designware_i2c.h | 35 ++++++++++ drivers/i2c/designware_i2c_pci.c | 79 +++++++++++++++++++++++ 4 files changed, 134 insertions(+), 89 deletions(-) create mode 100644 drivers/i2c/designware_i2c_pci.c diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index c2f75d8755..f5a471f887 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -14,6 +14,9 @@ obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_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_IHS) += ihs_i2c.o obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index 6daa90e744..b8cdd1c661 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -13,34 +13,6 @@ #include #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 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; 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; else if (speed >= I2C_FAST_SPEED) 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)); switch (i2c_spd) { -#ifndef CONFIG_X86 /* No High-speed for BayTrail yet */ case IC_SPEED_MODE_MAX: cntl |= IC_CON_SPD_SS; 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(lcnt, &i2c_base->ic_hs_scl_lcnt); break; -#endif case IC_SPEED_MODE_STANDARD: cntl |= IC_CON_SPD_SS; @@ -565,25 +537,20 @@ static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr, 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); 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); if (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); } -static int designware_i2c_remove(struct udevice *dev) +int designware_i2c_remove(struct udevice *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); } -static int designware_i2c_bind(struct udevice *dev) -{ - 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 = { +const struct dm_i2c_ops designware_i2c_ops = { .xfer = designware_i2c_xfer, .probe_chip = designware_i2c_probe_chip, .set_bus_speed = designware_i2c_set_bus_speed, @@ -656,28 +600,12 @@ U_BOOT_DRIVER(i2c_designware) = { .name = "i2c_designware", .id = UCLASS_I2C, .of_match = designware_i2c_ids, - .bind = designware_i2c_bind, + .ofdata_to_platdata = designware_i2c_ofdata_to_platdata, .probe = designware_i2c_probe, .priv_auto_alloc_size = sizeof(struct dw_i2c), .remove = designware_i2c_remove, - .flags = DM_FLAG_OS_PREPARE, + .flags = DM_FLAG_OS_PREPARE, .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 */ diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h index 20ff20d9b8..48766d0806 100644 --- a/drivers/i2c/designware_i2c.h +++ b/drivers/i2c/designware_i2c.h @@ -7,6 +7,8 @@ #ifndef __DW_I2C_H_ #define __DW_I2C_H_ +#include + struct i2c_regs { u32 ic_con; /* 0x00 */ u32 ic_tar; /* 0x04 */ @@ -131,4 +133,37 @@ struct i2c_regs { #define I2C_FAST_SPEED 400000 #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_ */ diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c new file mode 100644 index 0000000000..e8fc6f2a90 --- /dev/null +++ b/drivers/i2c/designware_i2c_pci.c @@ -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 +#include +#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);