1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2022 Linaro Ltd.
*/
#include <linux/io.h>
#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");
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->reg_addr = res->start;
ipa->regs = regs;
return 0;
}
void ipa_reg_exit(struct ipa *ipa)
{
iounmap(ipa->reg_virt);
}
|