|
26 | 26 | #include <linux/pm_runtime.h>
|
27 | 27 | #include <linux/resource.h>
|
28 | 28 | #include <linux/types.h>
|
| 29 | +#include <linux/mfd/syscon.h> |
| 30 | +#include <linux/regmap.h> |
29 | 31 |
|
30 | 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 | 575 | static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
532 | 576 | {
|
533 | 577 | u32 reg;
|
@@ -644,6 +688,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
644 | 688 | case DW_PCIE_EP_TYPE:
|
645 | 689 | dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
|
646 | 690 | DEVICE_TYPE_EP);
|
| 691 | + |
| 692 | + ret = dra7xx_pcie_ep_unaligned_memaccess(dev); |
| 693 | + if (ret) |
| 694 | + goto err_gpio; |
| 695 | + |
647 | 696 | ret = dra7xx_add_pcie_ep(dra7xx, pdev);
|
648 | 697 | if (ret < 0)
|
649 | 698 | goto err_gpio;
|
|
0 commit comments