diff options
author | Kishon Vijay Abraham I <kishon@ti.com> | 2017-03-27 05:45:11 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-04-28 11:23:18 -0400 |
commit | f7a2757f6cd0aa4e1075188a3a0081a583fcee24 (patch) | |
tree | b5d51ac2e92f66382054829e48d48b69b507b048 | |
parent | 40cc72e2b51f61956f965510ceba35bddb0c373f (diff) |
PCI: dwc: dra7xx: Workaround for errata id i870
According to errata i870, access to the PCIe slave port that are not 32-bit
aligned will result in incorrect mapping to TLP Address and Byte enable
fields.
Accessing non 32-bit aligned data causes incorrect data in the target
buffer if memcpy is used. Implement the workaround for this errata here.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r-- | drivers/pci/dwc/pci-dra7xx.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/drivers/pci/dwc/pci-dra7xx.c b/drivers/pci/dwc/pci-dra7xx.c index 35c18534469c..8decf46cf525 100644 --- a/drivers/pci/dwc/pci-dra7xx.c +++ b/drivers/pci/dwc/pci-dra7xx.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
27 | #include <linux/resource.h> | 27 | #include <linux/resource.h> |
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/mfd/syscon.h> | ||
30 | #include <linux/regmap.h> | ||
29 | 31 | ||
30 | #include "pcie-designware.h" | 32 | #include "pcie-designware.h" |
31 | 33 | ||
@@ -528,6 +530,48 @@ static const struct of_device_id of_dra7xx_pcie_match[] = { | |||
528 | {}, | 530 | {}, |
529 | }; | 531 | }; |
530 | 532 | ||
533 | /* | ||
534 | * dra7xx_pcie_ep_unaligned_memaccess: workaround for AM572x/AM571x Errata i870 | ||
535 | * @dra7xx: the dra7xx device where the workaround should be applied | ||
536 | * | ||
537 | * Access to the PCIe slave port that are not 32-bit aligned will result | ||
538 | * in incorrect mapping to TLP Address and Byte enable fields. Therefore, | ||
539 | * byte and half-word accesses are not possible to byte offset 0x1, 0x2, or | ||
540 | * 0x3. | ||
541 | * | ||
542 | * To avoid this issue set PCIE_SS1_AXI2OCP_LEGACY_MODE_ENABLE to 1. | ||
543 | */ | ||
544 | static int dra7xx_pcie_ep_unaligned_memaccess(struct device *dev) | ||
545 | { | ||
546 | int ret; | ||
547 | struct device_node *np = dev->of_node; | ||
548 | struct of_phandle_args args; | ||
549 | struct regmap *regmap; | ||
550 | |||
551 | regmap = syscon_regmap_lookup_by_phandle(np, | ||
552 | "ti,syscon-unaligned-access"); | ||
553 | if (IS_ERR(regmap)) { | ||
554 | dev_dbg(dev, "can't get ti,syscon-unaligned-access\n"); | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | |||
558 | ret = of_parse_phandle_with_fixed_args(np, "ti,syscon-unaligned-access", | ||
559 | 2, 0, &args); | ||
560 | if (ret) { | ||
561 | dev_err(dev, "failed to parse ti,syscon-unaligned-access\n"); | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | ret = regmap_update_bits(regmap, args.args[0], args.args[1], | ||
566 | args.args[1]); | ||
567 | if (ret) | ||
568 | dev_err(dev, "failed to enable unaligned access\n"); | ||
569 | |||
570 | of_node_put(args.np); | ||
571 | |||
572 | return ret; | ||
573 | } | ||
574 | |||
531 | static int __init dra7xx_pcie_probe(struct platform_device *pdev) | 575 | static int __init dra7xx_pcie_probe(struct platform_device *pdev) |
532 | { | 576 | { |
533 | u32 reg; | 577 | u32 reg; |
@@ -644,6 +688,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) | |||
644 | case DW_PCIE_EP_TYPE: | 688 | case DW_PCIE_EP_TYPE: |
645 | dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, | 689 | dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, |
646 | DEVICE_TYPE_EP); | 690 | DEVICE_TYPE_EP); |
691 | |||
692 | ret = dra7xx_pcie_ep_unaligned_memaccess(dev); | ||
693 | if (ret) | ||
694 | goto err_gpio; | ||
695 | |||
647 | ret = dra7xx_add_pcie_ep(dra7xx, pdev); | 696 | ret = dra7xx_add_pcie_ep(dra7xx, pdev); |
648 | if (ret < 0) | 697 | if (ret < 0) |
649 | goto err_gpio; | 698 | goto err_gpio; |