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 default: 113 return NULL; 114 } 115 } 116 117 /* Sets gsi->virt and I/O maps the "gsi" memory range for registers */ 118 int gsi_reg_init(struct gsi *gsi, struct platform_device *pdev) 119 { 120 struct device *dev = &pdev->dev; 121 struct resource *res; 122 resource_size_t size; 123 124 /* Get GSI memory range and map it */ 125 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsi"); 126 if (!res) { 127 dev_err(dev, "DT error getting \"gsi\" memory property\n"); 128 return -ENODEV; 129 } 130 131 size = resource_size(res); 132 if (res->start > U32_MAX || size > U32_MAX - res->start) { 133 dev_err(dev, "DT memory resource \"gsi\" out of range\n"); 134 return -EINVAL; 135 } 136 137 gsi->regs = gsi_regs(gsi); 138 if (!gsi->regs) { 139 dev_err(dev, "unsupported IPA version %u (?)\n", gsi->version); 140 return -EINVAL; 141 } 142 143 gsi->virt = ioremap(res->start, size); 144 if (!gsi->virt) { 145 dev_err(dev, "unable to remap \"gsi\" memory\n"); 146 return -ENOMEM; 147 } 148 149 return 0; 150 } 151 152 /* Inverse of gsi_reg_init() */ 153 void gsi_reg_exit(struct gsi *gsi) 154 { 155 iounmap(gsi->virt); 156 gsi->virt = NULL; 157 gsi->regs = NULL; 158 } 159