| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
|---|
| 2 | 2 | // Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. |
|---|
| 3 | 3 | |
|---|
| 4 | +#include <linux/acpi.h> |
|---|
| 4 | 5 | #include <linux/clk.h> |
|---|
| 5 | 6 | #include <linux/slab.h> |
|---|
| 6 | 7 | #include <linux/dma-mapping.h> |
|---|
| .. | .. |
|---|
| 90 | 91 | void __iomem *base; |
|---|
| 91 | 92 | struct clk_bulk_data ahb_clks[NUM_AHB_CLKS]; |
|---|
| 92 | 93 | }; |
|---|
| 94 | + |
|---|
| 95 | +static const char * const icc_path_names[] = {"qup-core", "qup-config", |
|---|
| 96 | + "qup-memory"}; |
|---|
| 93 | 97 | |
|---|
| 94 | 98 | #define QUP_HW_VER_REG 0x4 |
|---|
| 95 | 99 | |
|---|
| .. | .. |
|---|
| 215 | 219 | writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG); |
|---|
| 216 | 220 | } |
|---|
| 217 | 221 | |
|---|
| 222 | +static void geni_se_irq_clear(struct geni_se *se) |
|---|
| 223 | +{ |
|---|
| 224 | + writel_relaxed(0, se->base + SE_GSI_EVENT_EN); |
|---|
| 225 | + writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); |
|---|
| 226 | + writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); |
|---|
| 227 | + writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); |
|---|
| 228 | + writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); |
|---|
| 229 | + writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); |
|---|
| 230 | +} |
|---|
| 231 | + |
|---|
| 218 | 232 | /** |
|---|
| 219 | 233 | * geni_se_init() - Initialize the GENI serial engine |
|---|
| 220 | 234 | * @se: Pointer to the concerned serial engine. |
|---|
| .. | .. |
|---|
| 228 | 242 | { |
|---|
| 229 | 243 | u32 val; |
|---|
| 230 | 244 | |
|---|
| 245 | + geni_se_irq_clear(se); |
|---|
| 231 | 246 | geni_se_io_init(se->base); |
|---|
| 232 | 247 | geni_se_io_set_mode(se->base); |
|---|
| 233 | 248 | |
|---|
| .. | .. |
|---|
| 249 | 264 | u32 proto = geni_se_read_proto(se); |
|---|
| 250 | 265 | u32 val; |
|---|
| 251 | 266 | |
|---|
| 252 | | - writel_relaxed(0, se->base + SE_GSI_EVENT_EN); |
|---|
| 253 | | - writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); |
|---|
| 254 | | - writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); |
|---|
| 255 | | - writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); |
|---|
| 256 | | - writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); |
|---|
| 257 | | - writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); |
|---|
| 267 | + geni_se_irq_clear(se); |
|---|
| 258 | 268 | |
|---|
| 259 | 269 | val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); |
|---|
| 260 | 270 | if (proto != GENI_SE_UART) { |
|---|
| .. | .. |
|---|
| 278 | 288 | u32 proto = geni_se_read_proto(se); |
|---|
| 279 | 289 | u32 val; |
|---|
| 280 | 290 | |
|---|
| 281 | | - writel_relaxed(0, se->base + SE_GSI_EVENT_EN); |
|---|
| 282 | | - writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); |
|---|
| 283 | | - writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); |
|---|
| 284 | | - writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); |
|---|
| 285 | | - writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); |
|---|
| 286 | | - writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); |
|---|
| 291 | + geni_se_irq_clear(se); |
|---|
| 287 | 292 | |
|---|
| 288 | 293 | val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); |
|---|
| 289 | 294 | if (proto != GENI_SE_UART) { |
|---|
| .. | .. |
|---|
| 462 | 467 | { |
|---|
| 463 | 468 | int ret; |
|---|
| 464 | 469 | |
|---|
| 470 | + if (has_acpi_companion(se->dev)) |
|---|
| 471 | + return 0; |
|---|
| 472 | + |
|---|
| 465 | 473 | ret = pinctrl_pm_select_sleep_state(se->dev); |
|---|
| 466 | 474 | if (ret) |
|---|
| 467 | 475 | return ret; |
|---|
| .. | .. |
|---|
| 498 | 506 | int geni_se_resources_on(struct geni_se *se) |
|---|
| 499 | 507 | { |
|---|
| 500 | 508 | int ret; |
|---|
| 509 | + |
|---|
| 510 | + if (has_acpi_companion(se->dev)) |
|---|
| 511 | + return 0; |
|---|
| 501 | 512 | |
|---|
| 502 | 513 | ret = geni_se_clks_on(se); |
|---|
| 503 | 514 | if (ret) |
|---|
| .. | .. |
|---|
| 635 | 646 | struct geni_wrapper *wrapper = se->wrapper; |
|---|
| 636 | 647 | u32 val; |
|---|
| 637 | 648 | |
|---|
| 649 | + if (!wrapper) |
|---|
| 650 | + return -EINVAL; |
|---|
| 651 | + |
|---|
| 638 | 652 | *iova = dma_map_single(wrapper->dev, buf, len, DMA_TO_DEVICE); |
|---|
| 639 | 653 | if (dma_mapping_error(wrapper->dev, *iova)) |
|---|
| 640 | 654 | return -EIO; |
|---|
| .. | .. |
|---|
| 667 | 681 | { |
|---|
| 668 | 682 | struct geni_wrapper *wrapper = se->wrapper; |
|---|
| 669 | 683 | u32 val; |
|---|
| 684 | + |
|---|
| 685 | + if (!wrapper) |
|---|
| 686 | + return -EINVAL; |
|---|
| 670 | 687 | |
|---|
| 671 | 688 | *iova = dma_map_single(wrapper->dev, buf, len, DMA_FROM_DEVICE); |
|---|
| 672 | 689 | if (dma_mapping_error(wrapper->dev, *iova)) |
|---|
| .. | .. |
|---|
| 719 | 736 | } |
|---|
| 720 | 737 | EXPORT_SYMBOL(geni_se_rx_dma_unprep); |
|---|
| 721 | 738 | |
|---|
| 739 | +int geni_icc_get(struct geni_se *se, const char *icc_ddr) |
|---|
| 740 | +{ |
|---|
| 741 | + int i, err; |
|---|
| 742 | + const char *icc_names[] = {"qup-core", "qup-config", icc_ddr}; |
|---|
| 743 | + |
|---|
| 744 | + if (has_acpi_companion(se->dev)) |
|---|
| 745 | + return 0; |
|---|
| 746 | + |
|---|
| 747 | + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) { |
|---|
| 748 | + if (!icc_names[i]) |
|---|
| 749 | + continue; |
|---|
| 750 | + |
|---|
| 751 | + se->icc_paths[i].path = devm_of_icc_get(se->dev, icc_names[i]); |
|---|
| 752 | + if (IS_ERR(se->icc_paths[i].path)) |
|---|
| 753 | + goto err; |
|---|
| 754 | + } |
|---|
| 755 | + |
|---|
| 756 | + return 0; |
|---|
| 757 | + |
|---|
| 758 | +err: |
|---|
| 759 | + err = PTR_ERR(se->icc_paths[i].path); |
|---|
| 760 | + if (err != -EPROBE_DEFER) |
|---|
| 761 | + dev_err_ratelimited(se->dev, "Failed to get ICC path '%s': %d\n", |
|---|
| 762 | + icc_names[i], err); |
|---|
| 763 | + return err; |
|---|
| 764 | + |
|---|
| 765 | +} |
|---|
| 766 | +EXPORT_SYMBOL(geni_icc_get); |
|---|
| 767 | + |
|---|
| 768 | +int geni_icc_set_bw(struct geni_se *se) |
|---|
| 769 | +{ |
|---|
| 770 | + int i, ret; |
|---|
| 771 | + |
|---|
| 772 | + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) { |
|---|
| 773 | + ret = icc_set_bw(se->icc_paths[i].path, |
|---|
| 774 | + se->icc_paths[i].avg_bw, se->icc_paths[i].avg_bw); |
|---|
| 775 | + if (ret) { |
|---|
| 776 | + dev_err_ratelimited(se->dev, "ICC BW voting failed on path '%s': %d\n", |
|---|
| 777 | + icc_path_names[i], ret); |
|---|
| 778 | + return ret; |
|---|
| 779 | + } |
|---|
| 780 | + } |
|---|
| 781 | + |
|---|
| 782 | + return 0; |
|---|
| 783 | +} |
|---|
| 784 | +EXPORT_SYMBOL(geni_icc_set_bw); |
|---|
| 785 | + |
|---|
| 786 | +void geni_icc_set_tag(struct geni_se *se, u32 tag) |
|---|
| 787 | +{ |
|---|
| 788 | + int i; |
|---|
| 789 | + |
|---|
| 790 | + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) |
|---|
| 791 | + icc_set_tag(se->icc_paths[i].path, tag); |
|---|
| 792 | +} |
|---|
| 793 | +EXPORT_SYMBOL(geni_icc_set_tag); |
|---|
| 794 | + |
|---|
| 795 | +/* To do: Replace this by icc_bulk_enable once it's implemented in ICC core */ |
|---|
| 796 | +int geni_icc_enable(struct geni_se *se) |
|---|
| 797 | +{ |
|---|
| 798 | + int i, ret; |
|---|
| 799 | + |
|---|
| 800 | + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) { |
|---|
| 801 | + ret = icc_enable(se->icc_paths[i].path); |
|---|
| 802 | + if (ret) { |
|---|
| 803 | + dev_err_ratelimited(se->dev, "ICC enable failed on path '%s': %d\n", |
|---|
| 804 | + icc_path_names[i], ret); |
|---|
| 805 | + return ret; |
|---|
| 806 | + } |
|---|
| 807 | + } |
|---|
| 808 | + |
|---|
| 809 | + return 0; |
|---|
| 810 | +} |
|---|
| 811 | +EXPORT_SYMBOL(geni_icc_enable); |
|---|
| 812 | + |
|---|
| 813 | +int geni_icc_disable(struct geni_se *se) |
|---|
| 814 | +{ |
|---|
| 815 | + int i, ret; |
|---|
| 816 | + |
|---|
| 817 | + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) { |
|---|
| 818 | + ret = icc_disable(se->icc_paths[i].path); |
|---|
| 819 | + if (ret) { |
|---|
| 820 | + dev_err_ratelimited(se->dev, "ICC disable failed on path '%s': %d\n", |
|---|
| 821 | + icc_path_names[i], ret); |
|---|
| 822 | + return ret; |
|---|
| 823 | + } |
|---|
| 824 | + } |
|---|
| 825 | + |
|---|
| 826 | + return 0; |
|---|
| 827 | +} |
|---|
| 828 | +EXPORT_SYMBOL(geni_icc_disable); |
|---|
| 829 | + |
|---|
| 722 | 830 | static int geni_se_probe(struct platform_device *pdev) |
|---|
| 723 | 831 | { |
|---|
| 724 | 832 | struct device *dev = &pdev->dev; |
|---|
| .. | .. |
|---|
| 736 | 844 | if (IS_ERR(wrapper->base)) |
|---|
| 737 | 845 | return PTR_ERR(wrapper->base); |
|---|
| 738 | 846 | |
|---|
| 739 | | - wrapper->ahb_clks[0].id = "m-ahb"; |
|---|
| 740 | | - wrapper->ahb_clks[1].id = "s-ahb"; |
|---|
| 741 | | - ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks); |
|---|
| 742 | | - if (ret) { |
|---|
| 743 | | - dev_err(dev, "Err getting AHB clks %d\n", ret); |
|---|
| 744 | | - return ret; |
|---|
| 847 | + if (!has_acpi_companion(&pdev->dev)) { |
|---|
| 848 | + wrapper->ahb_clks[0].id = "m-ahb"; |
|---|
| 849 | + wrapper->ahb_clks[1].id = "s-ahb"; |
|---|
| 850 | + ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks); |
|---|
| 851 | + if (ret) { |
|---|
| 852 | + dev_err(dev, "Err getting AHB clks %d\n", ret); |
|---|
| 853 | + return ret; |
|---|
| 854 | + } |
|---|
| 745 | 855 | } |
|---|
| 746 | 856 | |
|---|
| 747 | 857 | dev_set_drvdata(dev, wrapper); |
|---|