diff options
Diffstat (limited to 'drivers/net/ipa/ipa_reg.c')
-rw-r--r-- | drivers/net/ipa/ipa_reg.c | 97 |
1 files changed, 96 insertions, 1 deletions
diff --git a/drivers/net/ipa/ipa_reg.c b/drivers/net/ipa/ipa_reg.c index e6147a1cd787..22f067741d9b 100644 --- a/drivers/net/ipa/ipa_reg.c +++ b/drivers/net/ipa/ipa_reg.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2020 Linaro Ltd. + * Copyright (C) 2019-2022 Linaro Ltd. */ #include <linux/io.h> @@ -9,11 +9,105 @@ #include "ipa.h" #include "ipa_reg.h" +/* Is this register valid and defined for the current IPA version? */ +static bool ipa_reg_valid(struct ipa *ipa, enum ipa_reg_id reg_id) +{ + enum ipa_version version = ipa->version; + bool valid; + + /* Check for bogus (out of range) register IDs */ + if ((u32)reg_id >= ipa->regs->reg_count) + return false; + + switch (reg_id) { + case IPA_BCR: + case COUNTER_CFG: + valid = version < IPA_VERSION_4_5; + break; + + case IPA_TX_CFG: + case FLAVOR_0: + case IDLE_INDICATION_CFG: + valid = version >= IPA_VERSION_3_5; + break; + + case QTIME_TIMESTAMP_CFG: + case TIMERS_XO_CLK_DIV_CFG: + case TIMERS_PULSE_GRAN_CFG: + valid = version >= IPA_VERSION_4_5; + break; + + case SRC_RSRC_GRP_45_RSRC_TYPE: + case DST_RSRC_GRP_45_RSRC_TYPE: + valid = version <= IPA_VERSION_3_1 || + version == IPA_VERSION_4_5; + break; + + case SRC_RSRC_GRP_67_RSRC_TYPE: + case DST_RSRC_GRP_67_RSRC_TYPE: + valid = version <= IPA_VERSION_3_1; + break; + + case ENDP_FILTER_ROUTER_HSH_CFG: + valid = version != IPA_VERSION_4_2; + break; + + case IRQ_SUSPEND_EN: + case IRQ_SUSPEND_CLR: + valid = version >= IPA_VERSION_3_1; + break; + + default: + valid = true; /* Others should be defined for all versions */ + break; + } + + /* To be valid, it must be defined */ + + return valid && ipa->regs->reg[reg_id]; +} + +const struct ipa_reg *ipa_reg(struct ipa *ipa, enum ipa_reg_id reg_id) +{ + if (WARN_ON(!ipa_reg_valid(ipa, reg_id))) + return NULL; + + return ipa->regs->reg[reg_id]; +} + +static const struct ipa_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_9: + return &ipa_regs_v4_9; + case IPA_VERSION_4_11: + return &ipa_regs_v4_11; + default: + return NULL; + } +} + int ipa_reg_init(struct ipa *ipa) { struct device *dev = &ipa->pdev->dev; + const struct ipa_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(ipa->pdev, IORESOURCE_MEM, "ipa-reg"); @@ -28,6 +122,7 @@ int ipa_reg_init(struct ipa *ipa) return -ENOMEM; } ipa->reg_addr = res->start; + ipa->regs = regs; return 0; } |