| // SPDX-License-Identifier: GPL-2.0 | |
| /* Copyright (C) 2023-2024 Linaro Ltd. */ | |
| #include <linux/io.h> | |
| #include <linux/platform_device.h> | |
| #include "gsi.h" | |
| #include "gsi_reg.h" | |
| #include "reg.h" | |
| /* Is this register ID valid for the current GSI version? */ | |
| static bool gsi_reg_id_valid(struct gsi *gsi, enum gsi_reg_id reg_id) | |
| { | |
| switch (reg_id) { | |
| case INTER_EE_SRC_CH_IRQ_MSK: | |
| case INTER_EE_SRC_EV_CH_IRQ_MSK: | |
| return gsi->version >= IPA_VERSION_3_5; | |
| case HW_PARAM_2: | |
| return gsi->version >= IPA_VERSION_3_5_1; | |
| case HW_PARAM_4: | |
| return gsi->version >= IPA_VERSION_5_0; | |
| case CH_C_CNTXT_0: | |
| case CH_C_CNTXT_1: | |
| case CH_C_CNTXT_2: | |
| case CH_C_CNTXT_3: | |
| case CH_C_QOS: | |
| case CH_C_SCRATCH_0: | |
| case CH_C_SCRATCH_1: | |
| case CH_C_SCRATCH_2: | |
| case CH_C_SCRATCH_3: | |
| case EV_CH_E_CNTXT_0: | |
| case EV_CH_E_CNTXT_1: | |
| case EV_CH_E_CNTXT_2: | |
| case EV_CH_E_CNTXT_3: | |
| case EV_CH_E_CNTXT_4: | |
| case EV_CH_E_CNTXT_8: | |
| case EV_CH_E_CNTXT_9: | |
| case EV_CH_E_CNTXT_10: | |
| case EV_CH_E_CNTXT_11: | |
| case EV_CH_E_CNTXT_12: | |
| case EV_CH_E_CNTXT_13: | |
| case EV_CH_E_SCRATCH_0: | |
| case EV_CH_E_SCRATCH_1: | |
| case CH_C_DOORBELL_0: | |
| case EV_CH_E_DOORBELL_0: | |
| case GSI_STATUS: | |
| case CH_CMD: | |
| case EV_CH_CMD: | |
| case GENERIC_CMD: | |
| case CNTXT_TYPE_IRQ: | |
| case CNTXT_TYPE_IRQ_MSK: | |
| case CNTXT_SRC_CH_IRQ: | |
| case CNTXT_SRC_CH_IRQ_MSK: | |
| case CNTXT_SRC_CH_IRQ_CLR: | |
| case CNTXT_SRC_EV_CH_IRQ: | |
| case CNTXT_SRC_EV_CH_IRQ_MSK: | |
| case CNTXT_SRC_EV_CH_IRQ_CLR: | |
| case CNTXT_SRC_IEOB_IRQ: | |
| case CNTXT_SRC_IEOB_IRQ_MSK: | |
| case CNTXT_SRC_IEOB_IRQ_CLR: | |
| case CNTXT_GLOB_IRQ_STTS: | |
| case CNTXT_GLOB_IRQ_EN: | |
| case CNTXT_GLOB_IRQ_CLR: | |
| case CNTXT_GSI_IRQ_STTS: | |
| case CNTXT_GSI_IRQ_EN: | |
| case CNTXT_GSI_IRQ_CLR: | |
| case CNTXT_INTSET: | |
| case ERROR_LOG: | |
| case ERROR_LOG_CLR: | |
| case CNTXT_SCRATCH_0: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| const struct reg *gsi_reg(struct gsi *gsi, enum gsi_reg_id reg_id) | |
| { | |
| if (WARN(!gsi_reg_id_valid(gsi, reg_id), "invalid reg %u\n", reg_id)) | |
| return NULL; | |
| return reg(gsi->regs, reg_id); | |
| } | |
| static const struct regs *gsi_regs(struct gsi *gsi) | |
| { | |
| switch (gsi->version) { | |
| case IPA_VERSION_3_1: | |
| return &gsi_regs_v3_1; | |
| case IPA_VERSION_3_5_1: | |
| return &gsi_regs_v3_5_1; | |
| case IPA_VERSION_4_2: | |
| return &gsi_regs_v4_0; | |
| case IPA_VERSION_4_5: | |
| case IPA_VERSION_4_7: | |
| return &gsi_regs_v4_5; | |
| case IPA_VERSION_4_9: | |
| return &gsi_regs_v4_9; | |
| case IPA_VERSION_4_11: | |
| return &gsi_regs_v4_11; | |
| case IPA_VERSION_5_0: | |
| case IPA_VERSION_5_2: | |
| case IPA_VERSION_5_5: | |
| return &gsi_regs_v5_0; | |
| default: | |
| return NULL; | |
| } | |
| } | |
| /* Sets gsi->virt and I/O maps the "gsi" memory range for registers */ | |
| int gsi_reg_init(struct gsi *gsi, struct platform_device *pdev) | |
| { | |
| struct device *dev = &pdev->dev; | |
| struct resource *res; | |
| resource_size_t size; | |
| /* Get GSI memory range and map it */ | |
| res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsi"); | |
| if (!res) { | |
| dev_err(dev, "DT error getting \"gsi\" memory property\n"); | |
| return -ENODEV; | |
| } | |
| size = resource_size(res); | |
| if (res->start > U32_MAX || size > U32_MAX - res->start) { | |
| dev_err(dev, "DT memory resource \"gsi\" out of range\n"); | |
| return -EINVAL; | |
| } | |
| gsi->regs = gsi_regs(gsi); | |
| if (!gsi->regs) { | |
| dev_err(dev, "unsupported IPA version %u (?)\n", gsi->version); | |
| return -EINVAL; | |
| } | |
| gsi->virt = ioremap(res->start, size); | |
| if (!gsi->virt) { | |
| dev_err(dev, "unable to remap \"gsi\" memory\n"); | |
| return -ENOMEM; | |
| } | |
| return 0; | |
| } | |
| /* Inverse of gsi_reg_init() */ | |
| void gsi_reg_exit(struct gsi *gsi) | |
| { | |
| iounmap(gsi->virt); | |
| gsi->virt = NULL; | |
| gsi->regs = NULL; | |
| } |