1 // SPDX-License-Identifier: GPL-2.0 2 3 /* Copyright (C) 2023 Linaro Ltd. */ 4 5 #include <linux/platform_device.h> 6 #include <linux/io.h> 7 8 #include "gsi.h" 9 #include "reg.h" 10 #include "gsi_reg.h" 11 12 /* GSI EE registers as a group are shifted downward by a fixed constant amount 13 * for IPA versions 4.5 and beyond. This applies to all GSI registers we use 14 * *except* the ones that disable inter-EE interrupts for channels and event 15 * channels. 16 * 17 * The "raw" (not adjusted) GSI register range is mapped, and a pointer to 18 * the mapped range is held in gsi->virt_raw. The inter-EE interrupt 19 * registers are accessed using that pointer. 20 * 21 * Most registers are accessed using gsi->virt, which is a copy of the "raw" 22 * pointer, adjusted downward by the fixed amount. 23 */ 24 #define GSI_EE_REG_ADJUST 0x0000d000 /* IPA v4.5+ */ 25 26 /* Is this register ID valid for the current GSI version? */ 27 static bool gsi_reg_id_valid(struct gsi *gsi, enum gsi_reg_id reg_id) 28 { 29 switch (reg_id) { 30 case INTER_EE_SRC_CH_IRQ_MSK: 31 case INTER_EE_SRC_EV_CH_IRQ_MSK: 32 case CH_C_CNTXT_0: 33 case CH_C_CNTXT_1: 34 case CH_C_CNTXT_2: 35 case CH_C_CNTXT_3: 36 case CH_C_QOS: 37 case CH_C_SCRATCH_0: 38 case CH_C_SCRATCH_1: 39 case CH_C_SCRATCH_2: 40 case CH_C_SCRATCH_3: 41 case EV_CH_E_CNTXT_0: 42 case EV_CH_E_CNTXT_1: 43 case EV_CH_E_CNTXT_2: 44 case EV_CH_E_CNTXT_3: 45 case EV_CH_E_CNTXT_4: 46 case EV_CH_E_CNTXT_8: 47 case EV_CH_E_CNTXT_9: 48 case EV_CH_E_CNTXT_10: 49 case EV_CH_E_CNTXT_11: 50 case EV_CH_E_CNTXT_12: 51 case EV_CH_E_CNTXT_13: 52 case EV_CH_E_SCRATCH_0: 53 case EV_CH_E_SCRATCH_1: 54 case CH_C_DOORBELL_0: 55 case EV_CH_E_DOORBELL_0: 56 case GSI_STATUS: 57 case CH_CMD: 58 case EV_CH_CMD: 59 case GENERIC_CMD: 60 case HW_PARAM_2: 61 case CNTXT_TYPE_IRQ: 62 case CNTXT_TYPE_IRQ_MSK: 63 case CNTXT_SRC_CH_IRQ: 64 case CNTXT_SRC_CH_IRQ_MSK: 65 case CNTXT_SRC_CH_IRQ_CLR: 66 case CNTXT_SRC_EV_CH_IRQ: 67 case CNTXT_SRC_EV_CH_IRQ_MSK: 68 case CNTXT_SRC_EV_CH_IRQ_CLR: 69 case CNTXT_SRC_IEOB_IRQ: 70 case CNTXT_SRC_IEOB_IRQ_MSK: 71 case CNTXT_SRC_IEOB_IRQ_CLR: 72 case CNTXT_GLOB_IRQ_STTS: 73 case CNTXT_GLOB_IRQ_EN: 74 case CNTXT_GLOB_IRQ_CLR: 75 case CNTXT_GSI_IRQ_STTS: 76 case CNTXT_GSI_IRQ_EN: 77 case CNTXT_GSI_IRQ_CLR: 78 case CNTXT_INTSET: 79 case ERROR_LOG: 80 case ERROR_LOG_CLR: 81 case CNTXT_SCRATCH_0: 82 return true; 83 84 default: 85 return false; 86 } 87 } 88 89 const struct reg *gsi_reg(struct gsi *gsi, enum gsi_reg_id reg_id) 90 { 91 if (WARN(!gsi_reg_id_valid(gsi, reg_id), "invalid reg %u\n", reg_id)) 92 return NULL; 93 94 return reg(gsi->regs, reg_id); 95 } 96 97 static const struct regs *gsi_regs(struct gsi *gsi) 98 { 99 switch (gsi->version) { 100 case IPA_VERSION_3_1: 101 return &gsi_regs_v3_1; 102 103 case IPA_VERSION_3_5_1: 104 return &gsi_regs_v3_5_1; 105 106 case IPA_VERSION_4_2: 107 return &gsi_regs_v4_0; 108 109 case IPA_VERSION_4_5: 110 case IPA_VERSION_4_7: 111 return &gsi_regs_v4_5; 112 113 case IPA_VERSION_4_9: 114 return &gsi_regs_v4_9; 115 116 case IPA_VERSION_4_11: 117 return &gsi_regs_v4_11; 118 119 default: 120 return NULL; 121 } 122 } 123 124 /* Sets gsi->virt_raw and gsi->virt, and I/O maps the "gsi" memory range */ 125 int gsi_reg_init(struct gsi *gsi, struct platform_device *pdev) 126 { 127 struct device *dev = &pdev->dev; 128 struct resource *res; 129 resource_size_t size; 130 u32 adjust; 131 132 /* Get GSI memory range and map it */ 133 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsi"); 134 if (!res) { 135 dev_err(dev, "DT error getting \"gsi\" memory property\n"); 136 return -ENODEV; 137 } 138 139 size = resource_size(res); 140 if (res->start > U32_MAX || size > U32_MAX - res->start) { 141 dev_err(dev, "DT memory resource \"gsi\" out of range\n"); 142 return -EINVAL; 143 } 144 145 /* Make sure we can make our pointer adjustment if necessary */ 146 adjust = gsi->version < IPA_VERSION_4_5 ? 0 : GSI_EE_REG_ADJUST; 147 if (res->start < adjust) { 148 dev_err(dev, "DT memory resource \"gsi\" too low (< %u)\n", 149 adjust); 150 return -EINVAL; 151 } 152 153 gsi->regs = gsi_regs(gsi); 154 if (!gsi->regs) { 155 dev_err(dev, "unsupported IPA version %u (?)\n", gsi->version); 156 return -EINVAL; 157 } 158 159 gsi->virt_raw = ioremap(res->start, size); 160 if (!gsi->virt_raw) { 161 dev_err(dev, "unable to remap \"gsi\" memory\n"); 162 return -ENOMEM; 163 } 164 /* Most registers are accessed using an adjusted register range */ 165 gsi->virt = gsi->virt_raw - adjust; 166 167 return 0; 168 } 169 170 /* Inverse of gsi_reg_init() */ 171 void gsi_reg_exit(struct gsi *gsi) 172 { 173 gsi->virt = NULL; 174 iounmap(gsi->virt_raw); 175 gsi->virt_raw = NULL; 176 } 177