Message ID | 1461219582-16788-6-git-send-email-sr@denx.de |
---|---|
State | Accepted |
Commit | ba5da550ae1d955e53691e51cd74a27331ca3b3c |
Delegated to: | Heiko Schocher |
Headers | show |
Hello Simon, Am 21.04.2016 um 08:19 schrieb Stefan Roese: > This patch adds support for the PCI(e) based I2C cores. Which can be > found for example on the Intel Bay Trail SoC. It has 7 I2C controllers > implemented as PCI devices. > > This patch also adds the fixed values for the timing registers for > BayTrail which are taken from the Linux designware I2C driver. > > Signed-off-by: Stefan Roese <sr@denx.de> > Cc: Simon Glass <sjg@chromium.org> > Cc: Bin Meng <bmeng.cn@gmail.com> > Cc: Marek Vasut <marex@denx.de> > Cc: Heiko Schocher <hs@denx.de> > --- > v4: > - Used new function dev_get_addr_ptr() in probe function > to avoid cast. > For this to work, this patch need to be applied: > http://patchwork.ozlabs.org/patch/612948/ Is it Ok for you, if I apply this patch through the i2c tree? Or do you want to pick up this patchserie? bye, Heiko > - Rebased on latest mainline > > drivers/i2c/designware_i2c.c | 118 ++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 106 insertions(+), 12 deletions(-) > > diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c > index d653eff..0c7cd0b 100644 > --- a/drivers/i2c/designware_i2c.c > +++ b/drivers/i2c/designware_i2c.c > @@ -8,11 +8,32 @@ > #include <common.h> > #include <dm.h> > #include <i2c.h> > +#include <pci.h> > #include <asm/io.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; > }; > > static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable) > @@ -43,6 +64,7 @@ static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable) > * Set the i2c speed. > */ > static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base, > + struct dw_scl_sda_cfg *scl_sda_cfg, > unsigned int speed) > { > unsigned int cntl; > @@ -62,34 +84,55 @@ 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_HS; > - hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; > + cntl |= IC_CON_SPD_SS; > + if (scl_sda_cfg) { > + hcnt = scl_sda_cfg->fs_hcnt; > + lcnt = scl_sda_cfg->fs_lcnt; > + } else { > + hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; > + lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; > + } > writel(hcnt, &i2c_base->ic_hs_scl_hcnt); > - lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; > writel(lcnt, &i2c_base->ic_hs_scl_lcnt); > break; > +#endif > > case IC_SPEED_MODE_STANDARD: > cntl |= IC_CON_SPD_SS; > - hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; > + if (scl_sda_cfg) { > + hcnt = scl_sda_cfg->ss_hcnt; > + lcnt = scl_sda_cfg->ss_lcnt; > + } else { > + hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; > + lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; > + } > writel(hcnt, &i2c_base->ic_ss_scl_hcnt); > - lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; > writel(lcnt, &i2c_base->ic_ss_scl_lcnt); > break; > > case IC_SPEED_MODE_FAST: > default: > cntl |= IC_CON_SPD_FS; > - hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; > + if (scl_sda_cfg) { > + hcnt = scl_sda_cfg->fs_hcnt; > + lcnt = scl_sda_cfg->fs_lcnt; > + } else { > + hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; > + lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; > + } > writel(hcnt, &i2c_base->ic_fs_scl_hcnt); > - lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; > writel(lcnt, &i2c_base->ic_fs_scl_lcnt); > break; > } > > writel(cntl, &i2c_base->ic_con); > > + /* Configure SDA Hold Time if required */ > + if (scl_sda_cfg) > + writel(scl_sda_cfg->sda_hold, &i2c_base->ic_sda_hold); > + > /* Enable back i2c now speed set */ > dw_i2c_enable(i2c_base, true); > > @@ -316,7 +359,7 @@ static void __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr) > writel(IC_TX_TL, &i2c_base->ic_tx_tl); > writel(IC_STOP_DET, &i2c_base->ic_intr_mask); > #ifndef CONFIG_DM_I2C > - __dw_i2c_set_bus_speed(i2c_base, speed); > + __dw_i2c_set_bus_speed(i2c_base, NULL, speed); > writel(slaveaddr, &i2c_base->ic_sar); > #endif > > @@ -357,7 +400,7 @@ static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap, > unsigned int speed) > { > adap->speed = speed; > - return __dw_i2c_set_bus_speed(i2c_get_base(adap), speed); > + return __dw_i2c_set_bus_speed(i2c_get_base(adap), NULL, speed); > } > > static void dw_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) > @@ -448,7 +491,7 @@ static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) > { > struct dw_i2c *i2c = dev_get_priv(bus); > > - return __dw_i2c_set_bus_speed(i2c->regs, speed); > + return __dw_i2c_set_bus_speed(i2c->regs, i2c->scl_sda_cfg, speed); > } > > static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr, > @@ -471,14 +514,48 @@ static int designware_i2c_probe(struct udevice *bus) > { > struct dw_i2c *priv = dev_get_priv(bus); > > - /* Save base address from device-tree */ > - priv->regs = (struct i2c_regs *)dev_get_addr(bus); > + 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 *)dev_get_addr_ptr(bus); > + } > > __dw_i2c_init(priv->regs, 0, 0); > > return 0; > } > > +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 = { > .xfer = designware_i2c_xfer, > .probe_chip = designware_i2c_probe_chip, > @@ -494,9 +571,26 @@ U_BOOT_DRIVER(i2c_designware) = { > .name = "i2c_designware", > .id = UCLASS_I2C, > .of_match = designware_i2c_ids, > + .bind = designware_i2c_bind, > .probe = designware_i2c_probe, > .priv_auto_alloc_size = sizeof(struct dw_i2c), > .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 */ >
On Thu, Apr 21, 2016 at 3:31 PM, Heiko Schocher <hs@denx.de> wrote: > Hello Simon, > > Am 21.04.2016 um 08:19 schrieb Stefan Roese: >> >> This patch adds support for the PCI(e) based I2C cores. Which can be >> found for example on the Intel Bay Trail SoC. It has 7 I2C controllers >> implemented as PCI devices. >> >> This patch also adds the fixed values for the timing registers for >> BayTrail which are taken from the Linux designware I2C driver. >> >> Signed-off-by: Stefan Roese <sr@denx.de> >> Cc: Simon Glass <sjg@chromium.org> >> Cc: Bin Meng <bmeng.cn@gmail.com> >> Cc: Marek Vasut <marex@denx.de> >> Cc: Heiko Schocher <hs@denx.de> >> --- >> v4: >> - Used new function dev_get_addr_ptr() in probe function >> to avoid cast. >> For this to work, this patch need to be applied: >> http://patchwork.ozlabs.org/patch/612948/ > > > Is it Ok for you, if I apply this patch through the i2c tree? > Or do you want to pick up this patchserie? > Heiko, please go ahead to pick up this series via i2c tree. Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
On 21 April 2016 at 02:14, Bin Meng <bmeng.cn@gmail.com> wrote: > On Thu, Apr 21, 2016 at 3:31 PM, Heiko Schocher <hs@denx.de> wrote: >> Hello Simon, >> >> Am 21.04.2016 um 08:19 schrieb Stefan Roese: >>> >>> This patch adds support for the PCI(e) based I2C cores. Which can be >>> found for example on the Intel Bay Trail SoC. It has 7 I2C controllers >>> implemented as PCI devices. >>> >>> This patch also adds the fixed values for the timing registers for >>> BayTrail which are taken from the Linux designware I2C driver. >>> >>> Signed-off-by: Stefan Roese <sr@denx.de> >>> Cc: Simon Glass <sjg@chromium.org> >>> Cc: Bin Meng <bmeng.cn@gmail.com> >>> Cc: Marek Vasut <marex@denx.de> >>> Cc: Heiko Schocher <hs@denx.de> >>> --- >>> v4: >>> - Used new function dev_get_addr_ptr() in probe function >>> to avoid cast. >>> For this to work, this patch need to be applied: >>> http://patchwork.ozlabs.org/patch/612948/ >> >> >> Is it Ok for you, if I apply this patch through the i2c tree? >> Or do you want to pick up this patchserie? >> > > Heiko, please go ahead to pick up this series via i2c tree. > > Reviewed-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org>
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index d653eff..0c7cd0b 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -8,11 +8,32 @@ #include <common.h> #include <dm.h> #include <i2c.h> +#include <pci.h> #include <asm/io.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; }; static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable) @@ -43,6 +64,7 @@ static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable) * Set the i2c speed. */ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base, + struct dw_scl_sda_cfg *scl_sda_cfg, unsigned int speed) { unsigned int cntl; @@ -62,34 +84,55 @@ 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_HS; - hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; + cntl |= IC_CON_SPD_SS; + if (scl_sda_cfg) { + hcnt = scl_sda_cfg->fs_hcnt; + lcnt = scl_sda_cfg->fs_lcnt; + } else { + hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; + lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; + } writel(hcnt, &i2c_base->ic_hs_scl_hcnt); - lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; writel(lcnt, &i2c_base->ic_hs_scl_lcnt); break; +#endif case IC_SPEED_MODE_STANDARD: cntl |= IC_CON_SPD_SS; - hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; + if (scl_sda_cfg) { + hcnt = scl_sda_cfg->ss_hcnt; + lcnt = scl_sda_cfg->ss_lcnt; + } else { + hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; + lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; + } writel(hcnt, &i2c_base->ic_ss_scl_hcnt); - lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; writel(lcnt, &i2c_base->ic_ss_scl_lcnt); break; case IC_SPEED_MODE_FAST: default: cntl |= IC_CON_SPD_FS; - hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; + if (scl_sda_cfg) { + hcnt = scl_sda_cfg->fs_hcnt; + lcnt = scl_sda_cfg->fs_lcnt; + } else { + hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; + lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; + } writel(hcnt, &i2c_base->ic_fs_scl_hcnt); - lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; writel(lcnt, &i2c_base->ic_fs_scl_lcnt); break; } writel(cntl, &i2c_base->ic_con); + /* Configure SDA Hold Time if required */ + if (scl_sda_cfg) + writel(scl_sda_cfg->sda_hold, &i2c_base->ic_sda_hold); + /* Enable back i2c now speed set */ dw_i2c_enable(i2c_base, true); @@ -316,7 +359,7 @@ static void __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr) writel(IC_TX_TL, &i2c_base->ic_tx_tl); writel(IC_STOP_DET, &i2c_base->ic_intr_mask); #ifndef CONFIG_DM_I2C - __dw_i2c_set_bus_speed(i2c_base, speed); + __dw_i2c_set_bus_speed(i2c_base, NULL, speed); writel(slaveaddr, &i2c_base->ic_sar); #endif @@ -357,7 +400,7 @@ static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap, unsigned int speed) { adap->speed = speed; - return __dw_i2c_set_bus_speed(i2c_get_base(adap), speed); + return __dw_i2c_set_bus_speed(i2c_get_base(adap), NULL, speed); } static void dw_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) @@ -448,7 +491,7 @@ static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { struct dw_i2c *i2c = dev_get_priv(bus); - return __dw_i2c_set_bus_speed(i2c->regs, speed); + return __dw_i2c_set_bus_speed(i2c->regs, i2c->scl_sda_cfg, speed); } static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr, @@ -471,14 +514,48 @@ static int designware_i2c_probe(struct udevice *bus) { struct dw_i2c *priv = dev_get_priv(bus); - /* Save base address from device-tree */ - priv->regs = (struct i2c_regs *)dev_get_addr(bus); + 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 *)dev_get_addr_ptr(bus); + } __dw_i2c_init(priv->regs, 0, 0); return 0; } +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 = { .xfer = designware_i2c_xfer, .probe_chip = designware_i2c_probe_chip, @@ -494,9 +571,26 @@ U_BOOT_DRIVER(i2c_designware) = { .name = "i2c_designware", .id = UCLASS_I2C, .of_match = designware_i2c_ids, + .bind = designware_i2c_bind, .probe = designware_i2c_probe, .priv_auto_alloc_size = sizeof(struct dw_i2c), .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 */
This patch adds support for the PCI(e) based I2C cores. Which can be found for example on the Intel Bay Trail SoC. It has 7 I2C controllers implemented as PCI devices. This patch also adds the fixed values for the timing registers for BayTrail which are taken from the Linux designware I2C driver. Signed-off-by: Stefan Roese <sr@denx.de> Cc: Simon Glass <sjg@chromium.org> Cc: Bin Meng <bmeng.cn@gmail.com> Cc: Marek Vasut <marex@denx.de> Cc: Heiko Schocher <hs@denx.de> --- v4: - Used new function dev_get_addr_ptr() in probe function to avoid cast. For this to work, this patch need to be applied: http://patchwork.ozlabs.org/patch/612948/ - Rebased on latest mainline drivers/i2c/designware_i2c.c | 118 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 12 deletions(-)