| /* |
| * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. |
| * |
| * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include <linux/of.h> |
| #include <linux/ioport.h> |
| #include <linux/qcom_scm.h> |
| #include "nss_dp_hal.h" |
| |
| /* |
| * nss_dp_hal_tcsr_base_get() |
| * Reads TCSR base address from DTS |
| */ |
| static uint32_t nss_dp_hal_tcsr_base_get(void) |
| { |
| uint32_t tcsr_base_addr = 0; |
| struct device_node *dp_cmn; |
| |
| /* |
| * Get reference to NSS dp common device node |
| */ |
| dp_cmn = of_find_node_by_name(NULL, "nss-dp-common"); |
| if (!dp_cmn) { |
| pr_info("%s: NSS DP common node not found\n", __func__); |
| return 0; |
| } |
| |
| if (of_property_read_u32(dp_cmn, "qcom,tcsr-base", &tcsr_base_addr)) { |
| pr_err("%s: error reading TCSR base\n", __func__); |
| } |
| of_node_put(dp_cmn); |
| |
| return tcsr_base_addr; |
| } |
| |
| /* |
| * nss_dp_hal_tcsr_set() |
| * Sets the TCSR axi cache override register |
| */ |
| static void nss_dp_hal_tcsr_set(void) |
| { |
| void __iomem *tcsr_addr = NULL; |
| uint32_t tcsr_base; |
| int err; |
| |
| tcsr_base = nss_dp_hal_tcsr_base_get(); |
| if (!tcsr_base) { |
| pr_err("%s: Unable to get TCSR base address\n", __func__); |
| return; |
| } |
| |
| /* |
| * Check if Trust Zone is enabled in the system. |
| * If yes, we need to go through SCM API call to program TCSR register. |
| * If TZ is not enabled, we can write to the register directly. |
| */ |
| if (qcom_scm_is_available()) { |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) |
| err = qcom_scm_tcsr_reg_write((tcsr_base + TCSR_GMAC_AXI_CACHE_OVERRIDE_OFFSET), |
| TCSR_GMAC_AXI_CACHE_OVERRIDE_VALUE); |
| #else |
| err = qti_scm_tcsr_reg_write((tcsr_base + TCSR_GMAC_AXI_CACHE_OVERRIDE_OFFSET), |
| TCSR_GMAC_AXI_CACHE_OVERRIDE_VALUE); |
| #endif |
| if (err) { |
| pr_err("%s: SCM TCSR write error: %d\n", __func__, err); |
| } |
| } else { |
| tcsr_addr = ioremap_nocache((tcsr_base + TCSR_GMAC_AXI_CACHE_OVERRIDE_OFFSET), |
| TCSR_GMAC_AXI_CACHE_OVERRIDE_REG_SIZE); |
| if (!tcsr_addr) { |
| pr_err("%s: ioremap failed\n", __func__); |
| return; |
| } |
| writel(TCSR_GMAC_AXI_CACHE_OVERRIDE_VALUE, tcsr_addr); |
| iounmap(tcsr_addr); |
| } |
| } |
| |
| /* |
| * nss_dp_hal_get_data_plane_ops() |
| * Return the data plane ops for registered data plane. |
| */ |
| struct nss_dp_data_plane_ops *nss_dp_hal_get_data_plane_ops(void) |
| { |
| return &nss_dp_gmac_ops; |
| } |
| |
| /* |
| * nss_dp_hal_init() |
| * Sets the gmac ops based on the GMAC type. |
| */ |
| bool nss_dp_hal_init(void) |
| { |
| /* |
| * Bail out on not supported platform |
| */ |
| if (!of_machine_is_compatible("qcom,ipq5018")) { |
| return false; |
| } |
| |
| nss_dp_hal_set_gmac_ops(&syn_gmac_ops, GMAC_HAL_TYPE_SYN_GMAC); |
| |
| /* |
| * Program the global GMAC AXI Cache override register |
| * for optimized AXI DMA operation. |
| */ |
| nss_dp_hal_tcsr_set(); |
| return true; |
| } |
| |
| /* |
| * nss_dp_hal_cleanup() |
| * Sets the gmac ops to NULL. |
| */ |
| void nss_dp_hal_cleanup(void) |
| { |
| nss_dp_hal_set_gmac_ops(NULL, GMAC_HAL_TYPE_SYN_GMAC); |
| } |