From: "Chai, Chong Yi" <chong.yi.c...@intel.com> --- features/soc/baytrail/baytrail.scc | 10 + ...esignware-I2C-to-be-probed-before-SMBus-f.patch | 54 ++++ ...i2c-designware-Fix-checkpatch.pl-warnings.patch | 51 ++++ ...i2c-designware-add-i2c-high-speed-support.patch | 234 +++++++++++++++ ...are-add-per-channel-speed-parameter-and-f.patch | 331 +++++++++++++++++++++ .../i2c-designware-cleanup-__i2c_dw_enable.patch | 54 ++++ ...2c-designware-cleanup-irq-handler-setting.patch | 53 ++++ ...are-explicitly-abort-running-operation-on.patch | 70 +++++ .../i2c-designware-improve-FIFO-performance.patch | 137 +++++++++ ...are-use-hardware-provided-Rx-Tx-FIFO-dept.patch | 220 ++++++++++++++ ...nware-use-symbolic-names-for-command-bits.patch | 50 ++++ 11 files changed, 1264 insertions(+) create mode 100644 features/soc/baytrail/i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch create mode 100644 features/soc/baytrail/i2c-designware-Fix-checkpatch.pl-warnings.patch create mode 100644 features/soc/baytrail/i2c-designware-add-i2c-high-speed-support.patch create mode 100644 features/soc/baytrail/i2c-designware-add-per-channel-speed-parameter-and-f.patch create mode 100644 features/soc/baytrail/i2c-designware-cleanup-__i2c_dw_enable.patch create mode 100644 features/soc/baytrail/i2c-designware-cleanup-irq-handler-setting.patch create mode 100644 features/soc/baytrail/i2c-designware-explicitly-abort-running-operation-on.patch create mode 100644 features/soc/baytrail/i2c-designware-improve-FIFO-performance.patch create mode 100644 features/soc/baytrail/i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch create mode 100644 features/soc/baytrail/i2c-designware-use-symbolic-names-for-command-bits.patch
diff --git a/features/soc/baytrail/baytrail.scc b/features/soc/baytrail/baytrail.scc index b1638a1..1e7c7f2 100644 --- a/features/soc/baytrail/baytrail.scc +++ b/features/soc/baytrail/baytrail.scc @@ -17,3 +17,13 @@ patch usb-dwc3-core-Fix-gadget-for-system-suspend-resume.patch patch usb-xhci-Change-how-we-indicate-a-host-supports-Link.patch patch usb-core-hub-Generate-uevent-for-overcurrent-event.patch patch usb-core-hub-Fix-checkpatch.pl-error.patch +patch i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch +patch i2c-designware-cleanup-irq-handler-setting.patch +patch i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch +patch i2c-designware-use-symbolic-names-for-command-bits.patch +patch i2c-designware-cleanup-__i2c_dw_enable.patch +patch i2c-designware-explicitly-abort-running-operation-on.patch +patch i2c-designware-improve-FIFO-performance.patch +patch i2c-designware-add-per-channel-speed-parameter-and-f.patch +patch i2c-designware-add-i2c-high-speed-support.patch +patch i2c-designware-Fix-checkpatch.pl-warnings.patch diff --git a/features/soc/baytrail/i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch b/features/soc/baytrail/i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch new file mode 100644 index 0000000..5c26d2d --- /dev/null +++ b/features/soc/baytrail/i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch @@ -0,0 +1,54 @@ +From aca3cf92cab6182363a365ac9d7987398c662d2b Mon Sep 17 00:00:00 2001 +From: Maurice Petallo <mauricex.r.peta...@intel.com> +Date: Tue, 17 Feb 2015 13:21:01 +0800 +Subject: [PATCH 042/164] i2c: allow Designware I2C to be probed before SMBus + for Baytrail + +When SMBus is enabled in Baytrail, it is being probed first before +all the Designware I2C devices. This means SMBus will take the first +available bus id which is 0 and then the I2C devices will take the +next succeeding bus ids. This should be fine as long as the I2C +devices bus ids are assigned dynamically. + +The problem arises when the I2C devices' bus ids are assigned +statically and the SMBus is probed first. The kernel will fail to +add the i2c adapter because something else, which in that case is +the SMBus, has taken the bus id that the i2c adapter is trying to +take. + +As mentioned in commit "i2c: designware-pci: use static bus num +allocation for baytrail", it is required for I2C devices' bus ids +to be assigned statically for LPE Audio to register the i2c properly. + +To resolve this, we either force the SMBus to take the next bus id +after all the designware I2C devices or we allow all the I2C devices +to be probed first before the SMBus. This patch implements the 2nd. + +Signed-off-by: Maurice Petallo <mauricex.r.peta...@intel.com> +--- + drivers/i2c/busses/Makefile | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index a08931f..26c50ea 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -12,7 +12,6 @@ obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o + obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o + obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o + obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o +-obj-$(CONFIG_I2C_I801) += i2c-i801.o + obj-$(CONFIG_I2C_ISCH) += i2c-isch.o + obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o + obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o +@@ -41,6 +40,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o + i2c-designware-platform-objs := i2c-designware-platdrv.o + obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o + i2c-designware-pci-objs := i2c-designware-pcidrv.o ++obj-$(CONFIG_I2C_I801) += i2c-i801.o + obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o + obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o + obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o +-- +1.7.7.6 + diff --git a/features/soc/baytrail/i2c-designware-Fix-checkpatch.pl-warnings.patch b/features/soc/baytrail/i2c-designware-Fix-checkpatch.pl-warnings.patch new file mode 100644 index 0000000..80effb4 --- /dev/null +++ b/features/soc/baytrail/i2c-designware-Fix-checkpatch.pl-warnings.patch @@ -0,0 +1,51 @@ +From 9f827d6746c3231a2e6c2a6f2a17fb371443cd2a Mon Sep 17 00:00:00 2001 +From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +Date: Fri, 21 Aug 2015 12:21:20 +0800 +Subject: [PATCH 155/164] i2c: designware: Fix checkpatch.pl warnings + +This commit is to fix the result of running scripts/checkpatch.pl against +0127-i2c-designware-add-per-channel-speed-parameter-and-f.patch + +Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +--- + drivers/i2c/busses/i2c-designware-pcidrv.c | 2 +- + drivers/i2c/busses/i2c-designware-platdrv.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c +index 2c22aef..c52028f 100644 +--- a/drivers/i2c/busses/i2c-designware-pcidrv.c ++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c +@@ -339,7 +339,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + u32 mode; + struct dw_pci_controller *controller; + struct dw_scl_sda_cfg *cfg; +- static int channel = 0; ++ static int channel; + + if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { + dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__, +diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c +index 084d6ec..e7a4214 100644 +--- a/drivers/i2c/busses/i2c-designware-platdrv.c ++++ b/drivers/i2c/busses/i2c-designware-platdrv.c +@@ -95,13 +95,13 @@ static void i2c_dw_parse_flags(char *flags) + i++; /* next channel */ + break; + default: +- pr_err("i2c-designware-platform: invalid " +- "flag %c for channel %d\n", *p, i); ++ pr_err("i2c-designware-platform: invalid flag %c for channel %d\n", ++ *p, i); + } + } + } + +-static int channel = 0; ++static int channel; + + static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) + { +-- +1.7.7.6 + diff --git a/features/soc/baytrail/i2c-designware-add-i2c-high-speed-support.patch b/features/soc/baytrail/i2c-designware-add-i2c-high-speed-support.patch new file mode 100644 index 0000000..e27076d --- /dev/null +++ b/features/soc/baytrail/i2c-designware-add-i2c-high-speed-support.patch @@ -0,0 +1,234 @@ +From e1cd14a14f6584985c3a27f69f220b4569364380 Mon Sep 17 00:00:00 2001 +From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +Date: Wed, 29 Jul 2015 18:15:01 +0800 +Subject: [PATCH 128/164] i2c: designware: add i2c high-speed support + +This patch enable the High-speed mode. + +Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +--- + drivers/i2c/busses/i2c-designware-core.c | 23 +++++++++++++++++++++++ + drivers/i2c/busses/i2c-designware-core.h | 6 ++++++ + drivers/i2c/busses/i2c-designware-pcidrv.c | 18 ++++++++++++++++-- + drivers/i2c/busses/i2c-designware-platdrv.c | 23 +++++++++++++++++++++-- + 4 files changed, 66 insertions(+), 4 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c +index c359775..2bf62db 100644 +--- a/drivers/i2c/busses/i2c-designware-core.c ++++ b/drivers/i2c/busses/i2c-designware-core.c +@@ -41,6 +41,7 @@ + */ + #define DW_IC_CON 0x0 + #define DW_IC_TAR 0x4 ++# define DW_IC_TAR_HS_MASTER (BIT(10) | BIT(11)) + #define DW_IC_DATA_CMD 0x10 + # define DW_IC_CMD_READ BIT(8) + # define DW_IC_CMD_STOP BIT(9) +@@ -49,6 +50,8 @@ + #define DW_IC_SS_SCL_LCNT 0x18 + #define DW_IC_FS_SCL_HCNT 0x1c + #define DW_IC_FS_SCL_LCNT 0x20 ++#define DW_IC_HS_SCL_HCNT 0x24 ++#define DW_IC_HS_SCL_LCNT 0x28 + #define DW_IC_INTR_STAT 0x2c + #define DW_IC_INTR_MASK 0x30 + #define DW_IC_RAW_INTR_STAT 0x34 +@@ -372,6 +375,23 @@ int i2c_dw_init(struct dw_i2c_dev *dev) + dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); + dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); + ++ if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) == ++ DW_IC_CON_SPEED_HIGH) { ++ if (((comp_param1 >> 2) & 3) != 3) { ++ dev_err(dev->dev, "High Speed not supported!\n"); ++ dev->master_cfg &= ~DW_IC_CON_SPEED_MASK; ++ dev->master_cfg |= DW_IC_CON_SPEED_FAST; ++ dev->high_speed = false; ++ } else if (dev->hs_hcnt && dev->hs_lcnt) { ++ hcnt = dev->hs_hcnt; ++ lcnt = dev->hs_lcnt; ++ dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT); ++ dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT); ++ dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n", ++ hcnt, lcnt); ++ } ++ } ++ + /* Configure SDA Hold Time if required */ + if (dev->sda_hold_time) { + reg = dw_readl(dev, DW_IC_COMP_VERSION); +@@ -438,6 +458,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) + ic_con &= ~DW_IC_CON_10BITADDR_MASTER; + } + ++ if (dev->high_speed) /* High speed */ ++ ic_tar |= DW_IC_TAR_HS_MASTER; /* Send master highspeed addr */ ++ + dw_writel(dev, ic_con, DW_IC_CON); + + /* +diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h +index 956641f..5bbe769 100644 +--- a/drivers/i2c/busses/i2c-designware-core.h ++++ b/drivers/i2c/busses/i2c-designware-core.h +@@ -31,6 +31,7 @@ + #define DW_IC_CON_SPEED_MASK 0x6 + #define DW_IC_CON_SPEED_STD 0x2 + #define DW_IC_CON_SPEED_FAST 0x4 ++#define DW_IC_CON_SPEED_HIGH 0x6 + #define DW_IC_CON_10BITADDR_MASTER 0x10 + #define DW_IC_CON_RESTART_EN 0x20 + #define DW_IC_CON_SLAVE_DISABLE 0x40 +@@ -66,6 +67,8 @@ + * @ss_lcnt: standard speed LCNT value + * @fs_hcnt: fast speed HCNT value + * @fs_lcnt: fast speed LCNT value ++ * @hs_hcnt: high speed HCNT value ++ * @hs_lcnt: high speed LCNT value + * + * HCNT and LCNT parameters can be used if the platform knows more accurate + * values than the one computed based only on the input clock frequency. +@@ -104,6 +107,9 @@ struct dw_i2c_dev { + u16 ss_lcnt; + u16 fs_hcnt; + u16 fs_lcnt; ++ u16 hs_hcnt; ++ u16 hs_lcnt; ++ bool high_speed; + }; + + #define ACCESS_SWAP 0x00000001 +diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c +index 0332baf..2c22aef 100644 +--- a/drivers/i2c/busses/i2c-designware-pcidrv.c ++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c +@@ -45,10 +45,11 @@ + + static char *flags; + module_param(flags, charp, 0444); +-MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfp]\n" ++MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfph]\n" + " s - standard speed (100KHz)\n" + " f - fast speed (400KHz)\n" +-" p - fast-plus speed (1000kHz)\n"); ++" p - fast-plus speed (1000kHz)\n" ++" h - high speed (3.4MHz)\n"); + + #define MAX_CHANNELS 7 + +@@ -57,6 +58,7 @@ enum i2c_speeds { + i2c_ss, + i2c_fs, + i2c_fplus, ++ i2c_hs + }; + + static struct chan_opts { +@@ -91,6 +93,8 @@ struct dw_scl_sda_cfg { + u32 fs_lcnt; + u32 fp_hcnt; + u32 fp_lcnt; ++ u32 hs_hcnt; ++ u32 hs_lcnt; + u32 sda_hold; + }; + +@@ -120,6 +124,8 @@ static struct dw_scl_sda_cfg byt_config = { + .fs_lcnt = 0x99, + .fp_hcnt = 0x1B, + .fp_lcnt = 0x3A, ++ .hs_hcnt = 0x06, ++ .hs_lcnt = 0x0C, + .sda_hold = 0x6, + }; + +@@ -242,6 +248,9 @@ static void i2c_dw_parse_flags(char *flags) + case 'p': + chan_opts[i].speed = i2c_fplus; + break; ++ case 'h': ++ chan_opts[i].speed = i2c_hs; ++ break; + case ':': + i++; /* next channel */ + break; +@@ -378,6 +387,9 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + } else if (chan_opts[channel].speed == i2c_fs || + chan_opts[channel].speed == i2c_fplus) { + mode = DW_IC_CON_SPEED_FAST; ++ } else if (chan_opts[channel].speed == i2c_hs) { ++ dev->high_speed = true; ++ mode = DW_IC_CON_SPEED_HIGH; + } else { /* speed not set - using default from dw_pci_controller */ + mode = controller->bus_cfg & DW_IC_CON_SPEED_MASK; + } +@@ -394,6 +406,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + dev->fs_hcnt = cfg->fs_hcnt; + dev->fs_lcnt = cfg->fs_lcnt; + } ++ dev->hs_hcnt = cfg->hs_hcnt; ++ dev->hs_lcnt = cfg->hs_lcnt; + dev->sda_hold_time = cfg->sda_hold; + } + +diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c +index 530b9d1..084d6ec 100644 +--- a/drivers/i2c/busses/i2c-designware-platdrv.c ++++ b/drivers/i2c/busses/i2c-designware-platdrv.c +@@ -45,10 +45,11 @@ + + static char *flags; + module_param(flags, charp, 0444); +-MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfp]\n" ++MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfph]\n" + " s - standard speed (100KHz)\n" + " f - fast speed (400KHz)\n" +-" p - fast-plus speed (1000kHz)\n"); ++" p - fast-plus speed (1000kHz)\n" ++" h - high speed (3.4MHz)\n"); + + #define MAX_CHANNELS 7 + +@@ -57,6 +58,7 @@ enum i2c_speeds { + i2c_ss, + i2c_fs, + i2c_fplus, ++ i2c_hs + }; + + static struct chan_opts { +@@ -86,6 +88,9 @@ static void i2c_dw_parse_flags(char *flags) + case 'p': + chan_opts[i].speed = i2c_fplus; + break; ++ case 'h': ++ chan_opts[i].speed = i2c_hs; ++ break; + case ':': + i++; /* next channel */ + break; +@@ -229,6 +234,20 @@ static int dw_i2c_probe(struct platform_device *pdev) + } else if (chan_opts[channel].speed == i2c_fs || + chan_opts[channel].speed == i2c_fplus) { + dev->master_cfg |= DW_IC_CON_SPEED_FAST; ++ } else if (chan_opts[channel].speed == i2c_hs) { ++ u32 ic_clk = dev->get_clk_rate_khz(dev); ++ u32 hs_hcnt, hs_lcnt; ++ hs_hcnt = (60 * ic_clk) / 1000000; ++ hs_lcnt = (120 * ic_clk) / 1000000; ++ if (hs_hcnt < 2) { ++ dev_warn(dev->dev, "Clock rate too low for high speed!\n"); ++ dev->master_cfg |= DW_IC_CON_SPEED_FAST; ++ } else { ++ dev->hs_hcnt = hs_hcnt; ++ dev->hs_lcnt = hs_lcnt; ++ dev->master_cfg |= DW_IC_CON_SPEED_HIGH; ++ dev->high_speed = true; ++ } + } else { + dev->master_cfg |= DW_IC_CON_SPEED_FAST; + } +-- +1.7.7.6 + diff --git a/features/soc/baytrail/i2c-designware-add-per-channel-speed-parameter-and-f.patch b/features/soc/baytrail/i2c-designware-add-per-channel-speed-parameter-and-f.patch new file mode 100644 index 0000000..410f3f9 --- /dev/null +++ b/features/soc/baytrail/i2c-designware-add-per-channel-speed-parameter-and-f.patch @@ -0,0 +1,331 @@ +From a6fae535b3d2d6a1a4997d69f2a7fefe4ed84bcf Mon Sep 17 00:00:00 2001 +From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +Date: Wed, 29 Jul 2015 18:14:53 +0800 +Subject: [PATCH 127/164] i2c: designware: add per-channel speed parameter and + fast-plus speed option + +This patch allows the I2C transfer speed to be configured via module +parameter for each channel available. + +This patch also enable the Fast-mode Plus. + +Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +--- + drivers/i2c/busses/i2c-designware-core.h | 1 + + drivers/i2c/busses/i2c-designware-pcidrv.c | 100 +++++++++++++++++++++++++- + drivers/i2c/busses/i2c-designware-platdrv.c | 82 ++++++++++++++++++++-- + 3 files changed, 174 insertions(+), 9 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h +index e59dc2c..956641f 100644 +--- a/drivers/i2c/busses/i2c-designware-core.h ++++ b/drivers/i2c/busses/i2c-designware-core.h +@@ -28,6 +28,7 @@ + + + #define DW_IC_CON_MASTER 0x1 ++#define DW_IC_CON_SPEED_MASK 0x6 + #define DW_IC_CON_SPEED_STD 0x2 + #define DW_IC_CON_SPEED_FAST 0x4 + #define DW_IC_CON_10BITADDR_MASTER 0x10 +diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c +index c87f40c..0332baf 100644 +--- a/drivers/i2c/busses/i2c-designware-pcidrv.c ++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c +@@ -43,6 +43,26 @@ + + #define DRIVER_NAME "i2c-designware-pci" + ++static char *flags; ++module_param(flags, charp, 0444); ++MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfp]\n" ++" s - standard speed (100KHz)\n" ++" f - fast speed (400KHz)\n" ++" p - fast-plus speed (1000kHz)\n"); ++ ++#define MAX_CHANNELS 7 ++ ++enum i2c_speeds { ++ i2c_none = 0, ++ i2c_ss, ++ i2c_fs, ++ i2c_fplus, ++}; ++ ++static struct chan_opts { ++ enum i2c_speeds speed; ++} chan_opts[MAX_CHANNELS]; ++ + enum dw_pci_ctl_id_t { + moorestown_0, + moorestown_1, +@@ -69,6 +89,8 @@ struct dw_scl_sda_cfg { + u32 fs_hcnt; + u32 ss_lcnt; + u32 fs_lcnt; ++ u32 fp_hcnt; ++ u32 fp_lcnt; + u32 sda_hold; + }; + +@@ -96,6 +118,8 @@ static struct dw_scl_sda_cfg byt_config = { + .fs_hcnt = 0x55, + .ss_lcnt = 0x200, + .fs_lcnt = 0x99, ++ .fp_hcnt = 0x1B, ++ .fp_lcnt = 0x3A, + .sda_hold = 0x6, + }; + +@@ -200,6 +224,34 @@ static struct i2c_algorithm i2c_dw_algo = { + .functionality = i2c_dw_func, + }; + ++static void i2c_dw_parse_flags(char *flags) ++{ ++ char *p = flags; ++ int i; ++ ++ for (i = 0; i < MAX_CHANNELS; p++) { ++ if (!*p) ++ break; ++ switch (*p) { ++ case 's': ++ chan_opts[i].speed = i2c_ss; ++ break; ++ case 'f': ++ chan_opts[i].speed = i2c_fs; ++ break; ++ case 'p': ++ chan_opts[i].speed = i2c_fplus; ++ break; ++ case ':': ++ i++; /* next channel */ ++ break; ++ default: ++ pr_err(DRIVER_NAME ": invalid flag %c for channel %d\n", ++ *p, i); ++ } ++ } ++} ++ + static int i2c_dw_pci_suspend(struct device *dev) + { + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); +@@ -275,8 +327,10 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + struct dw_i2c_dev *dev; + struct i2c_adapter *adap; + int r; ++ u32 mode; + struct dw_pci_controller *controller; + struct dw_scl_sda_cfg *cfg; ++ static int channel = 0; + + if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { + dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__, +@@ -313,13 +367,33 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + dev->functionality = controller->functionality | + DW_DEFAULT_FUNCTIONALITY; + +- dev->master_cfg = controller->bus_cfg; ++ if (channel >= MAX_CHANNELS) { ++ dev_warn(&pdev->dev, "Using default params\n"); ++ channel = MAX_CHANNELS - 1; ++ memset(&chan_opts[channel], 0, sizeof(struct chan_opts)); ++ } ++ ++ if (chan_opts[channel].speed == i2c_ss) { ++ mode = DW_IC_CON_SPEED_STD; ++ } else if (chan_opts[channel].speed == i2c_fs || ++ chan_opts[channel].speed == i2c_fplus) { ++ mode = DW_IC_CON_SPEED_FAST; ++ } else { /* speed not set - using default from dw_pci_controller */ ++ mode = controller->bus_cfg & DW_IC_CON_SPEED_MASK; ++ } ++ ++ dev->master_cfg = (controller->bus_cfg & ~DW_IC_CON_SPEED_MASK) | mode; + if (controller->scl_sda_cfg) { + cfg = controller->scl_sda_cfg; + dev->ss_hcnt = cfg->ss_hcnt; +- dev->fs_hcnt = cfg->fs_hcnt; + dev->ss_lcnt = cfg->ss_lcnt; +- dev->fs_lcnt = cfg->fs_lcnt; ++ if (chan_opts[channel].speed == i2c_fplus) { ++ dev->fs_hcnt = cfg->fp_hcnt; ++ dev->fs_lcnt = cfg->fp_lcnt; ++ } else { ++ dev->fs_hcnt = cfg->fs_hcnt; ++ dev->fs_lcnt = cfg->fs_lcnt; ++ } + dev->sda_hold_time = cfg->sda_hold; + } + +@@ -359,6 +433,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_allow(&pdev->dev); + ++ channel++; ++ + return 0; + } + +@@ -410,7 +486,23 @@ static struct pci_driver dw_i2c_driver = { + }, + }; + +-module_pci_driver(dw_i2c_driver); ++static int __init ++i2c_dw_pci_init(void) ++{ ++ if (flags) ++ i2c_dw_parse_flags(flags); ++ ++ return pci_register_driver(&dw_i2c_driver); ++} ++ ++static void __exit ++i2c_dw_pci_exit(void) ++{ ++ pci_unregister_driver(&dw_i2c_driver); ++} ++ ++module_init(i2c_dw_pci_init); ++module_exit(i2c_dw_pci_exit); + + MODULE_AUTHOR("Baruch Siach <bar...@tkos.co.il>"); + MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter"); +diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c +index e0f0c64..530b9d1 100644 +--- a/drivers/i2c/busses/i2c-designware-platdrv.c ++++ b/drivers/i2c/busses/i2c-designware-platdrv.c +@@ -43,10 +43,61 @@ + #include <linux/acpi.h> + #include "i2c-designware-core.h" + ++static char *flags; ++module_param(flags, charp, 0444); ++MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfp]\n" ++" s - standard speed (100KHz)\n" ++" f - fast speed (400KHz)\n" ++" p - fast-plus speed (1000kHz)\n"); ++ ++#define MAX_CHANNELS 7 ++ ++enum i2c_speeds { ++ i2c_none = 0, ++ i2c_ss, ++ i2c_fs, ++ i2c_fplus, ++}; ++ ++static struct chan_opts { ++ enum i2c_speeds speed; ++} chan_opts[MAX_CHANNELS]; ++ + static struct i2c_algorithm i2c_dw_algo = { + .master_xfer = i2c_dw_xfer, + .functionality = i2c_dw_func, + }; ++ ++static void i2c_dw_parse_flags(char *flags) ++{ ++ char *p = flags; ++ int i; ++ ++ for (i = 0; i < MAX_CHANNELS; p++) { ++ if (!*p) ++ break; ++ switch (*p) { ++ case 's': ++ chan_opts[i].speed = i2c_ss; ++ break; ++ case 'f': ++ chan_opts[i].speed = i2c_fs; ++ break; ++ case 'p': ++ chan_opts[i].speed = i2c_fplus; ++ break; ++ case ':': ++ i++; /* next channel */ ++ break; ++ default: ++ pr_err("i2c-designware-platform: invalid " ++ "flag %c for channel %d\n", *p, i); ++ } ++ } ++} ++ ++static int channel = 0; ++ + static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) + { + return clk_get_rate(dev->clk)/1000; +@@ -79,7 +130,6 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], + static int dw_i2c_acpi_configure(struct platform_device *pdev) + { + struct dw_i2c_dev *dev = platform_get_drvdata(pdev); +- bool fs_mode = dev->master_cfg & DW_IC_CON_SPEED_FAST; + + if (!ACPI_HANDLE(&pdev->dev)) + return -ENODEV; +@@ -91,9 +141,13 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) + * it exists for both supported speed modes. + */ + dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, +- fs_mode ? NULL : &dev->sda_hold_time); +- dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, +- fs_mode ? &dev->sda_hold_time : NULL); ++ NULL); ++ if (chan_opts[channel].speed == i2c_fplus) ++ dw_i2c_acpi_params(pdev, "FPCN", &dev->fs_hcnt, &dev->fs_lcnt, ++ &dev->sda_hold_time); ++ else ++ dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, ++ &dev->sda_hold_time); + + return 0; + } +@@ -162,7 +216,22 @@ static int dw_i2c_probe(struct platform_device *pdev) + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK; + dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | +- DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; ++ DW_IC_CON_RESTART_EN; ++ ++ if (channel >= MAX_CHANNELS) { ++ dev_warn(dev->dev, "Using default params\n"); ++ channel = MAX_CHANNELS - 1; ++ memset(&chan_opts[channel], 0, sizeof(struct chan_opts)); ++ } ++ ++ if (chan_opts[channel].speed == i2c_ss) { ++ dev->master_cfg |= DW_IC_CON_SPEED_STD; ++ } else if (chan_opts[channel].speed == i2c_fs || ++ chan_opts[channel].speed == i2c_fplus) { ++ dev->master_cfg |= DW_IC_CON_SPEED_FAST; ++ } else { ++ dev->master_cfg |= DW_IC_CON_SPEED_FAST; ++ } + + #ifdef CONFIG_ACPI + dw_i2c_acpi_configure(pdev); +@@ -203,6 +272,7 @@ static int dw_i2c_probe(struct platform_device *pdev) + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ++ channel++; + return 0; + } + +@@ -275,6 +345,8 @@ static struct platform_driver dw_i2c_driver = { + + static int __init dw_i2c_init_driver(void) + { ++ if (flags) ++ i2c_dw_parse_flags(flags); + return platform_driver_register(&dw_i2c_driver); + } + subsys_initcall(dw_i2c_init_driver); +-- +1.7.7.6 + diff --git a/features/soc/baytrail/i2c-designware-cleanup-__i2c_dw_enable.patch b/features/soc/baytrail/i2c-designware-cleanup-__i2c_dw_enable.patch new file mode 100644 index 0000000..92b2537 --- /dev/null +++ b/features/soc/baytrail/i2c-designware-cleanup-__i2c_dw_enable.patch @@ -0,0 +1,54 @@ +From a12e523011a2e92fe4a6c7e2be2047a1e1c64985 Mon Sep 17 00:00:00 2001 +From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +Date: Wed, 29 Jul 2015 18:14:25 +0800 +Subject: [PATCH 124/164] i2c: designware: cleanup __i2c_dw_enable() + +- Do not write boolean value to register (and implicitly depend on match + between boolean representation and register bit position). + +- Do not implicitly depend on same bit position of enable bit in Enable + and Enable Status registers. + +Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +--- + drivers/i2c/busses/i2c-designware-core.c | 9 +++++++-- + 1 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c +index d60d8da..896d711 100644 +--- a/drivers/i2c/busses/i2c-designware-core.c ++++ b/drivers/i2c/busses/i2c-designware-core.c +@@ -66,12 +66,14 @@ + #define DW_IC_CLR_START_DET 0x64 + #define DW_IC_CLR_GEN_CALL 0x68 + #define DW_IC_ENABLE 0x6c ++# define DW_IC_ENABLE_EN BIT(0) + #define DW_IC_STATUS 0x70 + #define DW_IC_TXFLR 0x74 + #define DW_IC_RXFLR 0x78 + #define DW_IC_SDA_HOLD 0x7c + #define DW_IC_TX_ABRT_SOURCE 0x80 + #define DW_IC_ENABLE_STATUS 0x9c ++# define DW_IC_ENABLE_STATUS_EN BIT(0) + #define DW_IC_COMP_PARAM_1 0xf4 + #define DW_IC_COMP_VERSION 0xf8 + #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A +@@ -259,10 +261,13 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) + static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) + { + int timeout = 100; ++ u32 status; + + do { +- dw_writel(dev, enable, DW_IC_ENABLE); +- if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable) ++ dw_writel(dev, enable ? DW_IC_ENABLE_EN : 0, DW_IC_ENABLE); ++ status = dw_readl(dev, DW_IC_ENABLE_STATUS); ++ if ((enable && (status & DW_IC_ENABLE_STATUS_EN)) || ++ (!enable && !(status & DW_IC_ENABLE_STATUS_EN))) + return; + + /* +-- +1.7.7.6 + diff --git a/features/soc/baytrail/i2c-designware-cleanup-irq-handler-setting.patch b/features/soc/baytrail/i2c-designware-cleanup-irq-handler-setting.patch new file mode 100644 index 0000000..da5ee02 --- /dev/null +++ b/features/soc/baytrail/i2c-designware-cleanup-irq-handler-setting.patch @@ -0,0 +1,53 @@ +From b4dd652adaf7192c7ef905b9f88692109311fdd0 Mon Sep 17 00:00:00 2001 +From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +Date: Wed, 29 Jul 2015 18:13:56 +0800 +Subject: [PATCH 121/164] i2c: designware: cleanup irq handler setting + +Disable irq and clear any pending interrupts both in PCI and platform +driver, do so before setting interrupt handler. + +Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +--- + drivers/i2c/busses/i2c-designware-pcidrv.c | 5 +++-- + drivers/i2c/busses/i2c-designware-platdrv.c | 2 ++ + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c +index bd7b6b7..4a2a2a3 100644 +--- a/drivers/i2c/busses/i2c-designware-pcidrv.c ++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c +@@ -375,6 +375,9 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + + snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci"); + ++ i2c_dw_disable_int(dev); ++ i2c_dw_clear_int(dev); ++ + r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED, + adap->name, dev); + if (r) { +@@ -382,8 +385,6 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + return r; + } + +- i2c_dw_disable_int(dev); +- i2c_dw_clear_int(dev); + r = i2c_add_numbered_adapter(adap); + if (r) { + dev_err(&pdev->dev, "failure adding adapter\n"); +diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c +index d0bdac0..9b9ce46 100644 +--- a/drivers/i2c/busses/i2c-designware-platdrv.c ++++ b/drivers/i2c/busses/i2c-designware-platdrv.c +@@ -185,6 +185,8 @@ static int dw_i2c_probe(struct platform_device *pdev) + return r; + + i2c_dw_disable_int(dev); ++ i2c_dw_clear_int(dev); ++ + r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED, + pdev->name, dev); + if (r) { +-- +1.7.7.6 + diff --git a/features/soc/baytrail/i2c-designware-explicitly-abort-running-operation-on.patch b/features/soc/baytrail/i2c-designware-explicitly-abort-running-operation-on.patch new file mode 100644 index 0000000..52bb9de --- /dev/null +++ b/features/soc/baytrail/i2c-designware-explicitly-abort-running-operation-on.patch @@ -0,0 +1,70 @@ +From 48423cfcaee8dcb7f313ca49bd11f2d7fa145f05 Mon Sep 17 00:00:00 2001 +From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +Date: Wed, 29 Jul 2015 18:14:34 +0800 +Subject: [PATCH 125/164] i2c: designware: explicitly abort running operation + on disable + +Failure to disable causes hard device hangs in some situations +involving timeouts. + +Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +--- + drivers/i2c/busses/i2c-designware-core.c | 19 ++++++++++++++++++- + 1 files changed, 18 insertions(+), 1 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c +index 896d711..f867c9b 100644 +--- a/drivers/i2c/busses/i2c-designware-core.c ++++ b/drivers/i2c/busses/i2c-designware-core.c +@@ -67,7 +67,9 @@ + #define DW_IC_CLR_GEN_CALL 0x68 + #define DW_IC_ENABLE 0x6c + # define DW_IC_ENABLE_EN BIT(0) ++# define DW_IC_ENABLE_ABRT BIT(1) + #define DW_IC_STATUS 0x70 ++# define DW_IC_STATUS_MST_ACT BIT(5) + #define DW_IC_TXFLR 0x74 + #define DW_IC_RXFLR 0x78 + #define DW_IC_SDA_HOLD 0x7c +@@ -174,6 +176,8 @@ static char *abort_sources[] = { + "lost arbitration", + }; + ++static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); ++ + u32 dw_readl(struct dw_i2c_dev *dev, int offset) + { + u32 value; +@@ -263,6 +267,17 @@ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) + int timeout = 100; + u32 status; + ++ if (!enable && ++ (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_MST_ACT)) { ++ /* Must abort if some activity is pending. */ ++ /* Enable first before */ ++ dw_writel(dev, DW_IC_ENABLE_EN, DW_IC_ENABLE); ++ /* aborting. */ ++ dw_writel(dev, DW_IC_ENABLE_EN | DW_IC_ENABLE_ABRT, ++ DW_IC_ENABLE); ++ i2c_dw_wait_bus_not_busy(dev); /* wait for abort completion */ ++ } ++ + do { + dw_writel(dev, enable ? DW_IC_ENABLE_EN : 0, DW_IC_ENABLE); + status = dw_readl(dev, DW_IC_ENABLE_STATUS); +@@ -642,8 +657,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) + dev->rx_outstanding = 0; + + ret = i2c_dw_wait_bus_not_busy(dev); +- if (ret < 0) ++ if (ret < 0) { ++ i2c_dw_disable(dev); + goto done; ++ } + + /* start the transfers */ + i2c_dw_xfer_init(dev); +-- +1.7.7.6 + diff --git a/features/soc/baytrail/i2c-designware-improve-FIFO-performance.patch b/features/soc/baytrail/i2c-designware-improve-FIFO-performance.patch new file mode 100644 index 0000000..5a546b3 --- /dev/null +++ b/features/soc/baytrail/i2c-designware-improve-FIFO-performance.patch @@ -0,0 +1,137 @@ +From cf20fd639b092e94c4ee55b8c7f80234df3419bf Mon Sep 17 00:00:00 2001 +From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +Date: Wed, 29 Jul 2015 18:14:43 +0800 +Subject: [PATCH 126/164] i2c: designware: improve FIFO performance + +There is no need to catch interrupt after every byte transmitted or +received, as driver currently does. Hardware has deep FIFOs that allow +much less software intervention. + +This patch reworks FIFO handling such that up to 3/4 of FIFO depth is +processed per one interrupt. This results into significant decrease of +number of interrupts and increase of performance. + +Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +--- + drivers/i2c/busses/i2c-designware-core.c | 34 ++++++++++++++++------------- + 1 files changed, 19 insertions(+), 15 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c +index f867c9b..c359775 100644 +--- a/drivers/i2c/busses/i2c-designware-core.c ++++ b/drivers/i2c/busses/i2c-designware-core.c +@@ -387,8 +387,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev) + dev->rx_fifo_depth = ((comp_param1 >> 8) & 0xff) + 1; + dev_dbg(dev->dev, "Tx/Rx FIFO sizes: %d/%d\n", + dev->tx_fifo_depth, dev->rx_fifo_depth); +- dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL); +- dw_writel(dev, 0, DW_IC_RX_TL); ++ dw_writel(dev, dev->tx_fifo_depth / 4, DW_IC_TX_TL); ++ dw_writel(dev, dev->rx_fifo_depth * 3 / 4, DW_IC_RX_TL); + + /* configure the i2c master */ + dw_writel(dev, dev->master_cfg , DW_IC_CON); +@@ -452,9 +452,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) + /* Enable the adapter */ + __i2c_dw_enable(dev, true); + +- /* Clear and enable interrupts */ ++ /* Clear interrupts, they will be enabled in 'xfer' function */ + i2c_dw_clear_int(dev); +- dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK); + } + + /* +@@ -511,7 +510,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) + } + + tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR); +- rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR); ++ rx_limit = dev->rx_fifo_depth - dev->rx_outstanding; + + while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { + u32 cmd = 0; +@@ -532,11 +531,6 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) + } + + if (msgs[dev->msg_write_idx].flags & I2C_M_RD) { +- +- /* avoid rx buffer overrun */ +- if (rx_limit - dev->rx_outstanding <= 0) +- break; +- + dw_writel(dev, cmd | DW_IC_CMD_READ, + DW_IC_DATA_CMD); + rx_limit--; +@@ -570,11 +564,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) + dw_writel(dev, intr_mask, DW_IC_INTR_MASK); + } + +-static void ++static int + i2c_dw_read(struct dw_i2c_dev *dev) + { + struct i2c_msg *msgs = dev->msgs; + int rx_valid; ++ int count = 0; + + for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) { + u32 len; +@@ -596,16 +591,19 @@ i2c_dw_read(struct dw_i2c_dev *dev) + for (; len > 0 && rx_valid > 0; len--, rx_valid--) { + *buf++ = dw_readl(dev, DW_IC_DATA_CMD); + dev->rx_outstanding--; ++ count++; + } + + if (len > 0) { + dev->status |= STATUS_READ_IN_PROGRESS; + dev->rx_buf_len = len; + dev->rx_buf = buf; +- return; ++ return count; + } else + dev->status &= ~STATUS_READ_IN_PROGRESS; + } ++ ++ return count; + } + + static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) +@@ -665,6 +663,8 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) + /* start the transfers */ + i2c_dw_xfer_init(dev); + ++ /* Fill up TX buffer and enable interrupts */ ++ i2c_dw_xfer_msg(dev); + /* wait for tx to complete */ + ret = wait_for_completion_timeout(&dev->cmd_complete, HZ); + if (ret == 0) { +@@ -781,6 +781,7 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) + { + struct dw_i2c_dev *dev = dev_id; + u32 stat, enabled; ++ int read_count = 0; + + enabled = dw_readl(dev, DW_IC_ENABLE); + stat = dw_readl(dev, DW_IC_RAW_INTR_STAT); +@@ -803,10 +804,13 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) + goto tx_aborted; + } + +- if (stat & DW_IC_INTR_RX_FULL) +- i2c_dw_read(dev); ++ if ((stat & (DW_IC_INTR_RX_FULL | DW_IC_INTR_STOP_DET)) || ++ dev->rx_outstanding) ++ read_count = i2c_dw_read(dev); + +- if (stat & DW_IC_INTR_TX_EMPTY) ++ /* Allow TX_EMPTY intr if TX queue is not empty */ ++ if ((read_count && dev->status & STATUS_WRITE_IN_PROGRESS) || ++ (stat & DW_IC_INTR_TX_EMPTY)) + i2c_dw_xfer_msg(dev); + + /* +-- +1.7.7.6 + diff --git a/features/soc/baytrail/i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch b/features/soc/baytrail/i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch new file mode 100644 index 0000000..c6b8fcd --- /dev/null +++ b/features/soc/baytrail/i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch @@ -0,0 +1,220 @@ +From 533841a28abf7d3feca8aee92478047d386755dc Mon Sep 17 00:00:00 2001 +From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +Date: Wed, 29 Jul 2015 18:14:05 +0800 +Subject: [PATCH 122/164] i2c: designware: use hardware-provided Rx/Tx FIFO + depths + +i2c-designware module provides information about actual Rx/Tx FIFO +depths in COMP_PARAM1 register. + +Current driver uses these hardware-provided values only in case of +non-ACPI platform device. For all other cases (which includes all +Bay Trail cases) hardcoded value of 32 is used instead - which leads to +suboptimal FIFO use. + +This patch switches to using hardware-provided values in all cases. + +Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +--- + drivers/i2c/busses/i2c-designware-core.c | 14 +++++++------- + drivers/i2c/busses/i2c-designware-core.h | 1 - + drivers/i2c/busses/i2c-designware-pcidrv.c | 24 ------------------------ + drivers/i2c/busses/i2c-designware-platdrv.c | 18 +++--------------- + 4 files changed, 10 insertions(+), 47 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c +index d95b930..f5d4ce3 100644 +--- a/drivers/i2c/busses/i2c-designware-core.c ++++ b/drivers/i2c/busses/i2c-designware-core.c +@@ -286,7 +286,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) + { + u32 input_clock_khz; + u32 hcnt, lcnt; +- u32 reg; ++ u32 reg, comp_param1; + + input_clock_khz = dev->get_clk_rate_khz(dev); + +@@ -303,6 +303,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev) + return -ENODEV; + } + ++ comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); ++ + /* Disable the adapter */ + __i2c_dw_enable(dev, false); + +@@ -358,6 +360,10 @@ int i2c_dw_init(struct dw_i2c_dev *dev) + } + + /* Configure Tx/Rx FIFO threshold levels */ ++ dev->tx_fifo_depth = ((comp_param1 >> 16) & 0xff) + 1; ++ dev->rx_fifo_depth = ((comp_param1 >> 8) & 0xff) + 1; ++ dev_dbg(dev->dev, "Tx/Rx FIFO sizes: %d/%d\n", ++ dev->tx_fifo_depth, dev->rx_fifo_depth); + dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL); + dw_writel(dev, 0, DW_IC_RX_TL); + +@@ -827,11 +833,5 @@ void i2c_dw_disable_int(struct dw_i2c_dev *dev) + } + EXPORT_SYMBOL_GPL(i2c_dw_disable_int); + +-u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev) +-{ +- return dw_readl(dev, DW_IC_COMP_PARAM_1); +-} +-EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); +- + MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h +index e8a7565..e59dc2c 100644 +--- a/drivers/i2c/busses/i2c-designware-core.h ++++ b/drivers/i2c/busses/i2c-designware-core.h +@@ -120,4 +120,3 @@ extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev); + extern void i2c_dw_disable(struct dw_i2c_dev *dev); + extern void i2c_dw_clear_int(struct dw_i2c_dev *dev); + extern void i2c_dw_disable_int(struct dw_i2c_dev *dev); +-extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); +diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c +index 385909e..4579a5e 100644 +--- a/drivers/i2c/busses/i2c-designware-pcidrv.c ++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c +@@ -69,8 +69,6 @@ struct dw_scl_sda_cfg { + struct dw_pci_controller { + u32 bus_num; + u32 bus_cfg; +- u32 tx_fifo_depth; +- u32 rx_fifo_depth; + u32 clk_khz; + u32 functionality; + struct dw_scl_sda_cfg *scl_sda_cfg; +@@ -99,71 +97,51 @@ static struct dw_pci_controller dw_pci_controllers[] = { + [moorestown_0] = { + .bus_num = 0, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 25000, + }, + [moorestown_1] = { + .bus_num = 1, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 25000, + }, + [moorestown_2] = { + .bus_num = 2, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 25000, + }, + [medfield_0] = { + .bus_num = 0, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 25000, + }, + [medfield_1] = { + .bus_num = 1, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 25000, + }, + [medfield_2] = { + .bus_num = 2, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 25000, + }, + [medfield_3] = { + .bus_num = 3, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 25000, + }, + [medfield_4] = { + .bus_num = 4, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 25000, + }, + [medfield_5] = { + .bus_num = 5, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 25000, + }, + [baytrail] = { + .bus_num = -1, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, +- .tx_fifo_depth = 32, +- .rx_fifo_depth = 32, + .clk_khz = 100000, + .functionality = I2C_FUNC_10BIT_ADDR, + .scl_sda_cfg = &byt_config, +@@ -299,8 +277,6 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + + pci_set_drvdata(pdev, dev); + +- dev->tx_fifo_depth = controller->tx_fifo_depth; +- dev->rx_fifo_depth = controller->rx_fifo_depth; + r = i2c_dw_init(dev); + if (r) + return r; +diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c +index 8aad948..3834bc2 100644 +--- a/drivers/i2c/busses/i2c-designware-platdrv.c ++++ b/drivers/i2c/busses/i2c-designware-platdrv.c +@@ -105,8 +105,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) + return -ENODEV; + + dev->adapter.nr = -1; +- dev->tx_fifo_depth = 32; +- dev->rx_fifo_depth = 32; + + /* + * Try to get SDA hold time and *CNT values from an ACPI method if +@@ -129,11 +127,6 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { + { } + }; + MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); +-#else +-static inline int dw_i2c_acpi_configure(struct platform_device *pdev) +-{ +- return -ENODEV; +-} + #endif + + static int dw_i2c_probe(struct platform_device *pdev) +@@ -191,15 +184,10 @@ static int dw_i2c_probe(struct platform_device *pdev) + dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | + DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; + +- /* Try first if we can configure the device from ACPI */ +- r = dw_i2c_acpi_configure(pdev); +- if (r) { +- u32 param1 = i2c_dw_read_comp_param(dev); ++#ifdef CONFIG_ACPI ++ dw_i2c_acpi_configure(pdev); ++#endif + +- dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; +- dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; +- dev->adapter.nr = pdev->id; +- } + r = i2c_dw_init(dev); + if (r) + return r; +-- +1.9.1 + + diff --git a/features/soc/baytrail/i2c-designware-use-symbolic-names-for-command-bits.patch b/features/soc/baytrail/i2c-designware-use-symbolic-names-for-command-bits.patch new file mode 100644 index 0000000..7f98525 --- /dev/null +++ b/features/soc/baytrail/i2c-designware-use-symbolic-names-for-command-bits.patch @@ -0,0 +1,50 @@ +From 548a004593a14b948af1dcff00ff013137511554 Mon Sep 17 00:00:00 2001 +From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +Date: Wed, 29 Jul 2015 18:14:14 +0800 +Subject: [PATCH 123/164] i2c: designware: use symbolic names for command bits + +Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com> +--- + drivers/i2c/busses/i2c-designware-core.c | 10 +++++++--- + 1 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c +index f5d4ce3..d60d8da 100644 +--- a/drivers/i2c/busses/i2c-designware-core.c ++++ b/drivers/i2c/busses/i2c-designware-core.c +@@ -42,6 +42,9 @@ + #define DW_IC_CON 0x0 + #define DW_IC_TAR 0x4 + #define DW_IC_DATA_CMD 0x10 ++# define DW_IC_CMD_READ BIT(8) ++# define DW_IC_CMD_STOP BIT(9) ++# define DW_IC_CMD_RESTART BIT(10) + #define DW_IC_SS_SCL_HCNT 0x14 + #define DW_IC_SS_SCL_LCNT 0x18 + #define DW_IC_FS_SCL_HCNT 0x1c +@@ -501,10 +504,10 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) + */ + if (dev->msg_write_idx == dev->msgs_num - 1 && + buf_len == 1) +- cmd |= BIT(9); ++ cmd |= DW_IC_CMD_STOP; + + if (need_restart) { +- cmd |= BIT(10); ++ cmd |= DW_IC_CMD_RESTART; + need_restart = false; + } + +@@ -514,7 +517,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) + if (rx_limit - dev->rx_outstanding <= 0) + break; + +- dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD); ++ dw_writel(dev, cmd | DW_IC_CMD_READ, ++ DW_IC_DATA_CMD); + rx_limit--; + dev->rx_outstanding++; + } else +-- +1.7.7.6 + -- 1.9.1 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto