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 /* Is this register ID valid for the current GSI version? */ 13 static bool gsi_reg_id_valid(struct gsi *gsi, enum gsi_reg_id reg_id) 14 { 15 switch (reg_id) { 16 case INTER_EE_SRC_CH_IRQ_MSK: 17 case INTER_EE_SRC_EV_CH_IRQ_MSK: 18 return gsi->version >= IPA_VERSION_3_5; 19 20 case HW_PARAM_2: 21 return gsi->version >= IPA_VERSION_3_5_1; 22 23 case HW_PARAM_4: 24 return gsi->version >= IPA_VERSION_5_0; 25 26 case CH_C_CNTXT_0: 27 case CH_C_CNTXT_1: 28 case CH_C_CNTXT_2: 29 case CH_C_CNTXT_3: 30 case CH_C_QOS: 31 case CH_C_SCRATCH_0: 32 case CH_C_SCRATCH_1: 33 case CH_C_SCRATCH_2: 34 case CH_C_SCRATCH_3: 35 case EV_CH_E_CNTXT_0: 36 case EV_CH_E_CNTXT_1: 37 case EV_CH_E_CNTXT_2: 38 case EV_CH_E_CNTXT_3: 39 case EV_CH_E_CNTXT_4: 40 case EV_CH_E_CNTXT_8: 41 case EV_CH_E_CNTXT_9: 42 case EV_CH_E_CNTXT_10: 43 case EV_CH_E_CNTXT_11: 44 case EV_CH_E_CNTXT_12: 45 case EV_CH_E_CNTXT_13: 46 case EV_CH_E_SCRATCH_0: 47 case EV_CH_E_SCRATCH_1: 48 case CH_C_DOORBELL_0: 49 case EV_CH_E_DOORBELL_0: 50 case GSI_STATUS: 51 case CH_CMD: 52 case EV_CH_CMD: 53 case GENERIC_CMD: 54 case CNTXT_TYPE_IRQ: 55 case CNTXT_TYPE_IRQ_MSK: 56 case CNTXT_SRC_CH_IRQ: 57 case CNTXT_SRC_CH_IRQ_MSK: 58 case CNTXT_SRC_CH_IRQ_CLR: 59 case CNTXT_SRC_EV_CH_IRQ: 60 case CNTXT_SRC_EV_CH_IRQ_MSK: 61 case CNTXT_SRC_EV_CH_IRQ_CLR: 62 case CNTXT_SRC_IEOB_IRQ: 63 case CNTXT_SRC_IEOB_IRQ_MSK: 64 case CNTXT_SRC_IEOB_IRQ_CLR: 65 case CNTXT_GLOB_IRQ_STTS: 66 case CNTXT_GLOB_IRQ_EN: 67 case CNTXT_GLOB_IRQ_CLR: 68 case CNTXT_GSI_IRQ_STTS: 69 case CNTXT_GSI_IRQ_EN: 70 case CNTXT_GSI_IRQ_CLR: 71 case CNTXT_INTSET: 72 case ERROR_LOG: 73 case ERROR_LOG_CLR: 74 case CNTXT_SCRATCH_0: 75 return true; 76 77 default: 78 return false; 79 } 80 } 81 82 const struct reg *gsi_reg(struct gsi *gsi, enum gsi_reg_id reg_id) 83 { 84 if (WARN(!gsi_reg_id_valid(gsi, reg_id), "invalid reg %u\n", reg_id)) 85 return NULL; 86 87 return reg(gsi->regs, reg_id); 88 } 89 90 static const struct regs *gsi_regs(struct gsi *gsi) 91 { 92 switch (gsi->version) { 93 case IPA_VERSION_3_1: 94 return &gsi_regs_v3_1; 95 96 case IPA_VERSION_3_5_1: 97 return &gsi_regs_v3_5_1; 98 99 case IPA_VERSION_4_2: 100 return &gsi_regs_v4_0; 101 102 case IPA_VERSION_4_5: 103 case IPA_VERSION_4_7: 104 return &gsi_regs_v4_5; 105 106 case IPA_VERSION_4_9: 107 return &gsi_regs_v4_9; 108 109 case IPA_VERSION_4_11: 110 return &gsi_regs_v4_11; 111 112 case IPA_VERSION_5_0: 113 return &gsi_regs_v5_0; 114 115 default: 116 return NULL; 117 } 118 } 119 120 /* Sets gsi->virt and I/O maps the "gsi" memory range for registers */ 121 int gsi_reg_init(struct gsi *gsi, struct platform_device *pdev) 122 { 123 struct device *dev = &pdev->dev; 124 struct resource *res; 125 resource_size_t size; 126 127 /* Get GSI memory range and map it */ 128 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsi"); 129 if (!res) { 130 dev_err(dev, "DT error getting \"gsi\" memory property\n"); 131 return -ENODEV; 132 } 133 134 size = resource_size(res); 135 if (res->start > U32_MAX || size > U32_MAX - res->start) { 136 dev_err(dev, "DT memory resource \"gsi\" out of range\n"); 137 return -EINVAL; 138 } 139 140 gsi->regs = gsi_regs(gsi); 141 if (!gsi->regs) { 142 dev_err(dev, "unsupported IPA version %u (?)\n", gsi->version); 143 return -EINVAL; 144 } 145 146 gsi->virt = ioremap(res->start, size); 147 if (!gsi->virt) { 148 dev_err(dev, "unable to remap \"gsi\" memory\n"); 149 return -ENOMEM; 150 } 151 152 return 0; 153 } 154 155 /* Inverse of gsi_reg_init() */ 156 void gsi_reg_exit(struct gsi *gsi) 157 { 158 iounmap(gsi->virt); 159 gsi->virt = NULL; 160 gsi->regs = NULL; 161 } 162