uboot/arch/arm/lib/gic-v3-its.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2019 Broadcom.
   4 */
   5#include <common.h>
   6#include <cpu_func.h>
   7#include <dm.h>
   8#include <asm/gic.h>
   9#include <asm/gic-v3.h>
  10#include <asm/io.h>
  11#include <linux/bitops.h>
  12#include <linux/sizes.h>
  13
  14static u32 lpi_id_bits;
  15
  16#define LPI_NRBITS              lpi_id_bits
  17#define LPI_PROPBASE_SZ         ALIGN(BIT(LPI_NRBITS), SZ_64K)
  18#define LPI_PENDBASE_SZ         ALIGN(BIT(LPI_NRBITS) / 8, SZ_64K)
  19
  20/*
  21 * gic_v3_its_priv - gic details
  22 *
  23 * @gicd_base: gicd base address
  24 * @gicr_base: gicr base address
  25 */
  26struct gic_v3_its_priv {
  27        ulong gicd_base;
  28        ulong gicr_base;
  29};
  30
  31static int gic_v3_its_get_gic_addr(struct gic_v3_its_priv *priv)
  32{
  33        struct udevice *dev;
  34        fdt_addr_t addr;
  35        int ret;
  36
  37        ret = uclass_get_device_by_driver(UCLASS_IRQ,
  38                                          DM_DRIVER_GET(arm_gic_v3_its), &dev);
  39        if (ret) {
  40                pr_err("%s: failed to get %s irq device\n", __func__,
  41                       DM_DRIVER_GET(arm_gic_v3_its)->name);
  42                return ret;
  43        }
  44
  45        addr = dev_read_addr_index(dev, 0);
  46        if (addr == FDT_ADDR_T_NONE) {
  47                pr_err("%s: failed to get GICD address\n", __func__);
  48                return -EINVAL;
  49        }
  50        priv->gicd_base = addr;
  51
  52        addr = dev_read_addr_index(dev, 1);
  53        if (addr == FDT_ADDR_T_NONE) {
  54                pr_err("%s: failed to get GICR address\n", __func__);
  55                return -EINVAL;
  56        }
  57        priv->gicr_base = addr;
  58
  59        return 0;
  60}
  61
  62/*
  63 * Program the GIC LPI configuration tables for all
  64 * the re-distributors and enable the LPI table
  65 * base: Configuration table address
  66 * num_redist: number of redistributors
  67 */
  68int gic_lpi_tables_init(u64 base, u32 num_redist)
  69{
  70        struct gic_v3_its_priv priv;
  71        u32 gicd_typer;
  72        u64 val;
  73        u64 tmp;
  74        int i;
  75        u64 redist_lpi_base;
  76        u64 pend_base;
  77        ulong pend_tab_total_sz = num_redist * LPI_PENDBASE_SZ;
  78        void *pend_tab_va;
  79
  80        if (gic_v3_its_get_gic_addr(&priv))
  81                return -EINVAL;
  82
  83        gicd_typer = readl((uintptr_t)(priv.gicd_base + GICD_TYPER));
  84        /* GIC support for Locality specific peripheral interrupts (LPI's) */
  85        if (!(gicd_typer & GICD_TYPER_LPIS)) {
  86                pr_err("GIC implementation does not support LPI's\n");
  87                return -EINVAL;
  88        }
  89
  90        /*
  91         * Check for LPI is disabled for all the redistributors.
  92         * Once the LPI table is enabled, can not program the
  93         * LPI configuration tables again, unless the GIC is reset.
  94         */
  95        for (i = 0; i < num_redist; i++) {
  96                u32 offset = i * GIC_REDISTRIBUTOR_OFFSET;
  97
  98                if ((readl((uintptr_t)(priv.gicr_base + offset))) &
  99                    GICR_CTLR_ENABLE_LPIS) {
 100                        pr_err("Re-Distributor %d LPI is already enabled\n",
 101                               i);
 102                        return -EINVAL;
 103                }
 104        }
 105
 106        /* lpi_id_bits to get LPI_PENDBASE_SZ and LPi_PROPBASE_SZ */
 107        lpi_id_bits = min_t(u32, GICD_TYPER_ID_BITS(gicd_typer),
 108                            ITS_MAX_LPI_NRBITS);
 109
 110        /* Set PropBase */
 111        val = (base |
 112               GICR_PROPBASER_INNERSHAREABLE |
 113               GICR_PROPBASER_RAWAWB |
 114               ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK));
 115
 116        writeq(val, (uintptr_t)(priv.gicr_base + GICR_PROPBASER));
 117        tmp = readl((uintptr_t)(priv.gicr_base + GICR_PROPBASER));
 118        if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) {
 119                if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) {
 120                        val &= ~(GICR_PROPBASER_SHAREABILITY_MASK |
 121                                GICR_PROPBASER_CACHEABILITY_MASK);
 122                        val |= GICR_PROPBASER_NC;
 123                        writeq(val,
 124                               (uintptr_t)(priv.gicr_base + GICR_PROPBASER));
 125                }
 126        }
 127
 128        redist_lpi_base = base + LPI_PROPBASE_SZ;
 129        pend_tab_va = map_physmem(redist_lpi_base, pend_tab_total_sz,
 130                                  MAP_NOCACHE);
 131        memset(pend_tab_va, 0, pend_tab_total_sz);
 132        flush_cache((ulong)pend_tab_va, pend_tab_total_sz);
 133        unmap_physmem(pend_tab_va, MAP_NOCACHE);
 134
 135        pend_base = priv.gicr_base + GICR_PENDBASER;
 136        for (i = 0; i < num_redist; i++) {
 137                u32 offset = i * GIC_REDISTRIBUTOR_OFFSET;
 138
 139                val = ((redist_lpi_base + (i * LPI_PENDBASE_SZ)) |
 140                        GICR_PENDBASER_INNERSHAREABLE |
 141                        GICR_PENDBASER_RAWAWB |
 142                        GICR_PENDBASER_PTZ);
 143
 144                writeq(val, (uintptr_t)(pend_base + offset));
 145                tmp = readq((uintptr_t)(pend_base + offset));
 146                if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) {
 147                        val &= ~(GICR_PENDBASER_SHAREABILITY_MASK |
 148                                 GICR_PENDBASER_CACHEABILITY_MASK);
 149                        val |= GICR_PENDBASER_NC;
 150                        writeq(val, (uintptr_t)(pend_base + offset));
 151                }
 152
 153                /* Enable LPI for the redistributor */
 154                writel(GICR_CTLR_ENABLE_LPIS,
 155                       (uintptr_t)(priv.gicr_base + offset));
 156        }
 157
 158        return 0;
 159}
 160
 161static const struct udevice_id gic_v3_its_ids[] = {
 162        { .compatible = "arm,gic-v3" },
 163        {}
 164};
 165
 166U_BOOT_DRIVER(arm_gic_v3_its) = {
 167        .name           = "gic-v3",
 168        .id             = UCLASS_IRQ,
 169        .of_match       = gic_v3_its_ids,
 170};
 171