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