| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) | 
| /* | 
|  * Copyright (c) 2023 Rockchip Electronics Co., Ltd. | 
|  */ | 
|   | 
| #include <linux/io.h> | 
| #include <linux/irqchip/arm-gic.h> | 
|   | 
| #include "rkpm_helpers.h" | 
| #include "rkpm_gicv2.h" | 
|   | 
| void rkpm_gicv2_dist_save(void __iomem *dist_base, | 
|               struct plat_gicv2_dist_ctx_t *ctx) | 
| { | 
|     int i; | 
|     int gic_irqs; | 
|   | 
|     gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f; | 
|     gic_irqs = (gic_irqs + 1) << 5; | 
|     if (gic_irqs > 1020) | 
|         gic_irqs = 1020; | 
|   | 
|     for (i = 32; i < gic_irqs; i += 4) | 
|         ctx->saved_spi_target[i >> 2] = | 
|             readl_relaxed(dist_base + GIC_DIST_TARGET + i); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 4) | 
|         ctx->saved_spi_prio[i >> 2] = | 
|             readl_relaxed(dist_base + GIC_DIST_PRI + i); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 16) | 
|         ctx->saved_spi_conf[i >> 4] = | 
|             readl_relaxed(dist_base + GIC_DIST_CONFIG + | 
|                      (i >> 4 << 2)); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 32) | 
|         ctx->saved_spi_grp[i >> 5] = | 
|             readl_relaxed(dist_base + GIC_DIST_IGROUP + | 
|                      (i >> 5 << 2)); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 32) | 
|         ctx->saved_spi_active[i >> 5] = | 
|             readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + | 
|                      (i >> 5 << 2)); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 32) | 
|         ctx->saved_spi_enable[i >> 5] = | 
|             readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + | 
|                      (i >> 5 << 2)); | 
|   | 
|     ctx->saved_gicd_ctrl = readl_relaxed(dist_base + GIC_DIST_CTRL); | 
| } | 
|   | 
| void rkpm_gicv2_dist_restore(void __iomem *dist_base, | 
|                  struct plat_gicv2_dist_ctx_t *ctx) | 
| { | 
|     int i = 0; | 
|     int gic_irqs; | 
|   | 
|     gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f; | 
|     gic_irqs = (gic_irqs + 1) << 5; | 
|     if (gic_irqs > 1020) | 
|         gic_irqs = 1020; | 
|   | 
|     writel_relaxed(0, dist_base + GIC_DIST_CTRL); | 
|     dsb(sy); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 4) | 
|         writel_relaxed(ctx->saved_spi_target[i >> 2], | 
|                    dist_base + GIC_DIST_TARGET + i); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 4) | 
|         writel_relaxed(ctx->saved_spi_prio[i >> 2], | 
|                    dist_base + GIC_DIST_PRI + i); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 16) | 
|         writel_relaxed(ctx->saved_spi_conf[i >> 4], | 
|                    dist_base + GIC_DIST_CONFIG + (i >> 4 << 2)); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 32) | 
|         writel_relaxed(ctx->saved_spi_grp[i >> 5], | 
|                    dist_base + GIC_DIST_IGROUP + (i >> 5 << 2)); | 
|   | 
|     for (i = 32; i < gic_irqs; i += 32) { | 
|         writel_relaxed(~0U, dist_base + GIC_DIST_ACTIVE_CLEAR + (i >> 5 << 2)); | 
|         dsb(sy); | 
|         writel_relaxed(ctx->saved_spi_active[i >> 5], | 
|                    dist_base + GIC_DIST_ACTIVE_SET + (i >> 5 << 2)); | 
|     } | 
|   | 
|     for (i = 32; i < gic_irqs; i += 32) { | 
|         writel_relaxed(~0U, dist_base + GIC_DIST_ENABLE_CLEAR + (i >> 5 << 2)); | 
|         dsb(sy); | 
|         writel_relaxed(ctx->saved_spi_enable[i >> 5], | 
|                    dist_base + GIC_DIST_ENABLE_SET + (i >> 5 << 2)); | 
|     } | 
|   | 
|     dsb(sy); | 
|   | 
|     writel_relaxed(ctx->saved_gicd_ctrl, dist_base + GIC_DIST_CTRL); | 
|     dsb(sy); | 
| } | 
|   | 
| void rkpm_gicv2_cpu_save(void __iomem *dist_base, | 
|              void __iomem *cpu_base, | 
|              struct plat_gicv2_cpu_ctx_t *ctx) | 
| { | 
|     int i; | 
|   | 
|     ctx->saved_ppi_enable = | 
|         readl_relaxed(dist_base + GIC_DIST_ENABLE_SET); | 
|   | 
|     ctx->saved_ppi_active = | 
|         readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET); | 
|   | 
|     for (i = 0; i < DIV_ROUND_UP(32, 16); i++) | 
|         ctx->saved_ppi_conf[i] = | 
|             readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4); | 
|   | 
|     for (i = 0; i < DIV_ROUND_UP(32, 4); i++) | 
|         ctx->saved_ppi_prio[i] = | 
|             readl_relaxed(dist_base + GIC_DIST_PRI + i * 4); | 
|   | 
|     ctx->saved_ppi_grp = | 
|             readl_relaxed(dist_base + GIC_DIST_IGROUP); | 
|   | 
|     ctx->saved_gicc_pmr = | 
|             readl_relaxed(cpu_base + GIC_CPU_PRIMASK); | 
|     ctx->saved_gicc_ctrl = | 
|             readl_relaxed(cpu_base + GIC_CPU_CTRL); | 
| } | 
|   | 
| void rkpm_gicv2_cpu_restore(void __iomem *dist_base, | 
|                 void __iomem *cpu_base, | 
|                 struct plat_gicv2_cpu_ctx_t *ctx) | 
| { | 
|     int i; | 
|   | 
|     writel_relaxed(0, cpu_base + GIC_CPU_CTRL); | 
|     dsb(sy); | 
|   | 
|     writel_relaxed(~0U, dist_base + GIC_DIST_ENABLE_CLEAR); | 
|     dsb(sy); | 
|     writel_relaxed(ctx->saved_ppi_enable, dist_base + GIC_DIST_ENABLE_SET); | 
|   | 
|     writel_relaxed(~0U, dist_base + GIC_DIST_ACTIVE_CLEAR); | 
|     dsb(sy); | 
|     writel_relaxed(ctx->saved_ppi_active, dist_base + GIC_DIST_ACTIVE_SET); | 
|   | 
|     for (i = 0; i < DIV_ROUND_UP(32, 16); i++) | 
|         writel_relaxed(ctx->saved_ppi_conf[i], dist_base + GIC_DIST_CONFIG + i * 4); | 
|   | 
|     for (i = 0; i < DIV_ROUND_UP(32, 4); i++) | 
|         writel_relaxed(ctx->saved_ppi_prio[i], dist_base + GIC_DIST_PRI + i * 4); | 
|   | 
|     writel_relaxed(ctx->saved_ppi_grp, dist_base + GIC_DIST_IGROUP); | 
|     writel_relaxed(ctx->saved_gicc_pmr, cpu_base + GIC_CPU_PRIMASK); | 
|     dsb(sy); | 
|   | 
|     writel_relaxed(ctx->saved_gicc_ctrl, cpu_base + GIC_CPU_CTRL); | 
|     dsb(sy); | 
| } |