| // SPDX-License-Identifier: GPL-2.0 | |
| /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. | |
| * Copyright (C) 2019-2024 Linaro Ltd. | |
| */ | |
| #include <linux/io.h> | |
| #include <linux/platform_device.h> | |
| #include "ipa.h" | |
| #include "ipa_reg.h" | |
| /* Is this register ID valid for the current IPA version? */ | |
| static bool ipa_reg_id_valid(struct ipa *ipa, enum ipa_reg_id reg_id) | |
| { | |
| enum ipa_version version = ipa->version; | |
| switch (reg_id) { | |
| case FILT_ROUT_HASH_EN: | |
| return version == IPA_VERSION_4_2; | |
| case FILT_ROUT_HASH_FLUSH: | |
| return version < IPA_VERSION_5_0 && version != IPA_VERSION_4_2; | |
| case FILT_ROUT_CACHE_FLUSH: | |
| case ENDP_FILTER_CACHE_CFG: | |
| case ENDP_ROUTER_CACHE_CFG: | |
| return version >= IPA_VERSION_5_0; | |
| case IPA_BCR: | |
| case COUNTER_CFG: | |
| return version < IPA_VERSION_4_5; | |
| case IPA_TX_CFG: | |
| case FLAVOR_0: | |
| case IDLE_INDICATION_CFG: | |
| return version >= IPA_VERSION_3_5; | |
| case QTIME_TIMESTAMP_CFG: | |
| case TIMERS_XO_CLK_DIV_CFG: | |
| case TIMERS_PULSE_GRAN_CFG: | |
| return version >= IPA_VERSION_4_5; | |
| case SRC_RSRC_GRP_45_RSRC_TYPE: | |
| case DST_RSRC_GRP_45_RSRC_TYPE: | |
| return version <= IPA_VERSION_3_1 || | |
| version == IPA_VERSION_4_5 || | |
| version >= IPA_VERSION_5_0; | |
| case SRC_RSRC_GRP_67_RSRC_TYPE: | |
| case DST_RSRC_GRP_67_RSRC_TYPE: | |
| return version <= IPA_VERSION_3_1 || | |
| version >= IPA_VERSION_5_0; | |
| case ENDP_FILTER_ROUTER_HSH_CFG: | |
| return version < IPA_VERSION_5_0 && | |
| version != IPA_VERSION_4_2; | |
| case IRQ_SUSPEND_EN: | |
| case IRQ_SUSPEND_CLR: | |
| return version >= IPA_VERSION_3_1; | |
| case COMP_CFG: | |
| case CLKON_CFG: | |
| case ROUTE: | |
| case SHARED_MEM_SIZE: | |
| case QSB_MAX_WRITES: | |
| case QSB_MAX_READS: | |
| case STATE_AGGR_ACTIVE: | |
| case LOCAL_PKT_PROC_CNTXT: | |
| case AGGR_FORCE_CLOSE: | |
| case SRC_RSRC_GRP_01_RSRC_TYPE: | |
| case SRC_RSRC_GRP_23_RSRC_TYPE: | |
| case DST_RSRC_GRP_01_RSRC_TYPE: | |
| case DST_RSRC_GRP_23_RSRC_TYPE: | |
| case ENDP_INIT_CTRL: | |
| case ENDP_INIT_CFG: | |
| case ENDP_INIT_NAT: | |
| case ENDP_INIT_HDR: | |
| case ENDP_INIT_HDR_EXT: | |
| case ENDP_INIT_HDR_METADATA_MASK: | |
| case ENDP_INIT_MODE: | |
| case ENDP_INIT_AGGR: | |
| case ENDP_INIT_HOL_BLOCK_EN: | |
| case ENDP_INIT_HOL_BLOCK_TIMER: | |
| case ENDP_INIT_DEAGGR: | |
| case ENDP_INIT_RSRC_GRP: | |
| case ENDP_INIT_SEQ: | |
| case ENDP_STATUS: | |
| case IPA_IRQ_STTS: | |
| case IPA_IRQ_EN: | |
| case IPA_IRQ_CLR: | |
| case IPA_IRQ_UC: | |
| case IRQ_SUSPEND_INFO: | |
| return true; /* These should be defined for all versions */ | |
| default: | |
| return false; | |
| } | |
| } | |
| const struct reg *ipa_reg(struct ipa *ipa, enum ipa_reg_id reg_id) | |
| { | |
| if (WARN(!ipa_reg_id_valid(ipa, reg_id), "invalid reg %u\n", reg_id)) | |
| return NULL; | |
| return reg(ipa->regs, reg_id); | |
| } | |
| static const struct regs *ipa_regs(enum ipa_version version) | |
| { | |
| switch (version) { | |
| case IPA_VERSION_3_1: | |
| return &ipa_regs_v3_1; | |
| case IPA_VERSION_3_5_1: | |
| return &ipa_regs_v3_5_1; | |
| case IPA_VERSION_4_2: | |
| return &ipa_regs_v4_2; | |
| case IPA_VERSION_4_5: | |
| return &ipa_regs_v4_5; | |
| case IPA_VERSION_4_7: | |
| return &ipa_regs_v4_7; | |
| case IPA_VERSION_4_9: | |
| return &ipa_regs_v4_9; | |
| case IPA_VERSION_4_11: | |
| return &ipa_regs_v4_11; | |
| case IPA_VERSION_5_0: | |
| case IPA_VERSION_5_2: | |
| return &ipa_regs_v5_0; | |
| case IPA_VERSION_5_5: | |
| return &ipa_regs_v5_5; | |
| default: | |
| return NULL; | |
| } | |
| } | |
| int ipa_reg_init(struct ipa *ipa, struct platform_device *pdev) | |
| { | |
| struct device *dev = &pdev->dev; | |
| const struct regs *regs; | |
| struct resource *res; | |
| regs = ipa_regs(ipa->version); | |
| if (!regs) | |
| return -EINVAL; | |
| if (WARN_ON(regs->reg_count > IPA_REG_ID_COUNT)) | |
| return -EINVAL; | |
| /* Setup IPA register memory */ | |
| res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ipa-reg"); | |
| if (!res) { | |
| dev_err(dev, "DT error getting \"ipa-reg\" memory property\n"); | |
| return -ENODEV; | |
| } | |
| ipa->reg_virt = ioremap(res->start, resource_size(res)); | |
| if (!ipa->reg_virt) { | |
| dev_err(dev, "unable to remap \"ipa-reg\" memory\n"); | |
| return -ENOMEM; | |
| } | |
| ipa->regs = regs; | |
| return 0; | |
| } | |
| void ipa_reg_exit(struct ipa *ipa) | |
| { | |
| iounmap(ipa->reg_virt); | |
| } |