From 457df2337fc90431dc60b9b256ac1fdb8809f4cf Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Dec 2019 21:41:40 -0700 Subject: 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/designware_i2c_pci.c | 79 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 drivers/i2c/designware_i2c_pci.c (limited to 'drivers/i2c/designware_i2c_pci.c') diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c new file mode 100644 index 00000000000..e8fc6f2a907 --- /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); -- cgit v1.2.3 From 8d72d5bf08488ff28a8ed27389dae8a169c39190 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Dec 2019 21:41:41 -0700 Subject: i2c: designware: Avoid using static data Drivers are not allowed to use static data since they may be used in SPL where BSS is not available. It is possible that driver model may provide support for numbering devices in the future. But for now, move this to global_data. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/i2c/designware_i2c_pci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/i2c/designware_i2c_pci.c') diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c index e8fc6f2a907..8d6bb37f5c4 100644 --- a/drivers/i2c/designware_i2c_pci.c +++ b/drivers/i2c/designware_i2c_pci.c @@ -34,7 +34,6 @@ static int designware_i2c_pci_probe(struct udevice *dev) static int designware_i2c_pci_bind(struct udevice *dev) { - static int num_cards; char name[20]; /* @@ -45,9 +44,13 @@ static int designware_i2c_pci_bind(struct udevice *dev) * using this driver is impossible for PCIe I2C devices. * This can be removed, once a better (correct) way for this * is found and implemented. + * + * TODO(sjg@chromium.org): Perhaps if uclasses had platdata this would + * be possible. We cannot use static data in drivers since they may be + * used in SPL or before relocation. */ - dev->req_seq = num_cards; - sprintf(name, "i2c_designware#%u", num_cards++); + dev->req_seq = gd->arch.dw_i2c_num_cards++; + sprintf(name, "i2c_designware#%u", dev->req_seq); device_set_name(dev, name); return 0; -- cgit v1.2.3 From fa11fe1b03a57e00073986b74813a74aa5b89290 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Dec 2019 21:41:42 -0700 Subject: i2c: designware: Support use in SPL Allow this driver to set up an IO address in SPL using an 'early-regs' property. This allows SPL to use the I2C driver without having to enable the full PCI stack. Also split out ofdata_to_platdata in designware driver since this is more correct, and more convenient for the new logic. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/i2c/designware_i2c_pci.c | 43 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers/i2c/designware_i2c_pci.c') diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c index 8d6bb37f5c4..bb1f809af3c 100644 --- a/drivers/i2c/designware_i2c_pci.c +++ b/drivers/i2c/designware_i2c_pci.c @@ -7,6 +7,7 @@ #include #include +#include #include "designware_i2c.h" /* BayTrail HCNT/LCNT/SDA hold time */ @@ -18,17 +19,46 @@ static struct dw_scl_sda_cfg byt_config = { .sda_hold = 0x6, }; -static int designware_i2c_pci_probe(struct udevice *dev) +static int designware_i2c_pci_ofdata_to_platdata(struct udevice *dev) { struct dw_i2c *priv = dev_get_priv(dev); + if (spl_phase() < PHASE_SPL) { + u32 base; + int ret; + + ret = dev_read_u32(dev, "early-regs", &base); + if (ret) + return log_msg_ret("early-regs", ret); + + /* Set i2c base address */ + dm_pci_write_config32(dev, PCI_BASE_ADDRESS_0, base); + + /* Enable memory access and bus master */ + dm_pci_write_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + } + + if (spl_phase() < PHASE_BOARD_F) { + /* Handle early, fixed mapping into a different address space */ + priv->regs = (struct i2c_regs *)dm_pci_read_bar32(dev, 0); + } else { + priv->regs = (struct i2c_regs *) + dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM); + } + if (!priv->regs) + return -EINVAL; + /* 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 0; +} + +static int designware_i2c_pci_probe(struct udevice *dev) +{ return designware_i2c_probe(dev); } @@ -56,10 +86,17 @@ static int designware_i2c_pci_bind(struct udevice *dev) return 0; } +static const struct udevice_id designware_i2c_pci_ids[] = { + { .compatible = "snps,designware-i2c-pci" }, + { } +}; + U_BOOT_DRIVER(i2c_designware_pci) = { .name = "i2c_designware_pci", .id = UCLASS_I2C, + .of_match = designware_i2c_pci_ids, .bind = designware_i2c_pci_bind, + .ofdata_to_platdata = designware_i2c_pci_ofdata_to_platdata, .probe = designware_i2c_pci_probe, .priv_auto_alloc_size = sizeof(struct dw_i2c), .remove = designware_i2c_remove, -- cgit v1.2.3 From 070a94600855d895e3aef97a0acfbf4d8fca26e8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 10 Dec 2019 21:28:20 -0700 Subject: i2c: designware: Add Apollo Lake support For Apollo Lake we need to take the I2C bus controller out of reset before using this. Add this functionality to the driver. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher Reviewed-by: Bin Meng --- drivers/i2c/designware_i2c_pci.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/i2c/designware_i2c_pci.c') diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c index bb1f809af3c..7f0625df66b 100644 --- a/drivers/i2c/designware_i2c_pci.c +++ b/drivers/i2c/designware_i2c_pci.c @@ -8,8 +8,14 @@ #include #include #include +#include #include "designware_i2c.h" +enum { + VANILLA = 0, /* standard I2C with no tweaks */ + INTEL_APL, /* Apollo Lake I2C */ +}; + /* BayTrail HCNT/LCNT/SDA hold time */ static struct dw_scl_sda_cfg byt_config = { .ss_hcnt = 0x200, @@ -19,6 +25,9 @@ static struct dw_scl_sda_cfg byt_config = { .sda_hold = 0x6, }; +/* Have a weak function for now - possibly should be a new uclass */ +__weak void lpss_reset_release(void *regs); + static int designware_i2c_pci_ofdata_to_platdata(struct udevice *dev) { struct dw_i2c *priv = dev_get_priv(dev); @@ -59,6 +68,15 @@ static int designware_i2c_pci_ofdata_to_platdata(struct udevice *dev) static int designware_i2c_pci_probe(struct udevice *dev) { + struct dw_i2c *priv = dev_get_priv(dev); + + if (dev_get_driver_data(dev) == INTEL_APL) { + /* Ensure controller is in D0 state */ + lpss_set_power_state(dev, STATE_D0); + + lpss_reset_release(priv->regs); + } + return designware_i2c_probe(dev); } @@ -88,6 +106,7 @@ static int designware_i2c_pci_bind(struct udevice *dev) static const struct udevice_id designware_i2c_pci_ids[] = { { .compatible = "snps,designware-i2c-pci" }, + { .compatible = "intel,apl-i2c", .data = INTEL_APL }, { } }; @@ -113,6 +132,12 @@ static struct pci_device_id designware_pci_supported[] = { { PCI_VDEVICE(INTEL, 0x0f45) }, { PCI_VDEVICE(INTEL, 0x0f46) }, { PCI_VDEVICE(INTEL, 0x0f47) }, + { PCI_VDEVICE(INTEL, 0x5aac), .driver_data = INTEL_APL }, + { PCI_VDEVICE(INTEL, 0x5aae), .driver_data = INTEL_APL }, + { PCI_VDEVICE(INTEL, 0x5ab0), .driver_data = INTEL_APL }, + { PCI_VDEVICE(INTEL, 0x5ab2), .driver_data = INTEL_APL }, + { PCI_VDEVICE(INTEL, 0x5ab4), .driver_data = INTEL_APL }, + { PCI_VDEVICE(INTEL, 0x5ab6), .driver_data = INTEL_APL }, {}, }; -- cgit v1.2.3