developer | 2fddd72 | 2022-05-20 11:22:21 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | * Copyright (C) 2022 MediaTek Inc. All rights reserved. |
| 4 | * |
| 5 | * Author: Weijie Gao <weijie.gao@mediatek.com> |
| 6 | */ |
| 7 | |
| 8 | #include <asm/io.h> |
| 9 | #include <asm/addrspace.h> |
| 10 | #include <asm/mipsregs.h> |
| 11 | #include <asm/cm.h> |
| 12 | #include <linux/bitfield.h> |
| 13 | #include "../mt7621.h" |
| 14 | |
| 15 | /* GIC Shared Register Bases */ |
| 16 | #define GIC_SH_POL_BASE 0x100 |
| 17 | #define GIC_SH_TRIG_BASE 0x180 |
| 18 | #define GIC_SH_RMASK_BASE 0x300 |
| 19 | #define GIC_SH_SMASK_BASE 0x380 |
| 20 | #define GIC_SH_MASK_BASE 0x400 |
| 21 | #define GIC_SH_PEND_BASE 0x480 |
| 22 | #define GIC_SH_MAP_PIN_BASE 0x500 |
| 23 | #define GIC_SH_MAP_VPE_BASE 0x2000 |
| 24 | |
| 25 | /* GIC Registers */ |
| 26 | #define GIC_SH_POL31_0 (GIC_SH_POL_BASE + 0x00) |
| 27 | #define GIC_SH_POL63_32 (GIC_SH_POL_BASE + 0x04) |
| 28 | |
| 29 | #define GIC_SH_TRIG31_0 (GIC_SH_TRIG_BASE + 0x00) |
| 30 | #define GIC_SH_TRIG63_32 (GIC_SH_TRIG_BASE + 0x04) |
| 31 | |
| 32 | #define GIC_SH_RMASK31_0 (GIC_SH_RMASK_BASE + 0x00) |
| 33 | #define GIC_SH_RMASK63_32 (GIC_SH_RMASK_BASE + 0x04) |
| 34 | |
| 35 | #define GIC_SH_SMASK31_0 (GIC_SH_SMASK_BASE + 0x00) |
| 36 | #define GIC_SH_SMASK63_32 (GIC_SH_SMASK_BASE + 0x04) |
| 37 | |
| 38 | #define GIC_SH_MAP_PIN(n) (GIC_SH_MAP_PIN_BASE + (n) * 4) |
| 39 | |
| 40 | #define GIC_SH_MAP_VPE(n, v) (GIC_SH_MAP_VPE_BASE + (n) * 0x20 + ((v) / 32) * 4) |
| 41 | #define GIC_SH_MAP_VPE31_0(n) GIC_SH_MAP_VPE(n, 0) |
| 42 | |
| 43 | /* GIC_SH_MAP_PIN fields */ |
| 44 | #define GIC_MAP_TO_PIN BIT(31) |
| 45 | #define GIC_MAP_TO_NMI BIT(30) |
| 46 | #define GIC_MAP GENMASK(5, 0) |
| 47 | #define GIC_MAP_SHIFT 0 |
| 48 | |
| 49 | static void cm_init(void __iomem *cm_base) |
| 50 | { |
| 51 | u32 gcrcfg, num_cores; |
| 52 | |
| 53 | gcrcfg = readl(cm_base + GCR_CONFIG); |
| 54 | num_cores = FIELD_GET(GCR_CONFIG_PCORES, gcrcfg) + 1; |
| 55 | |
| 56 | writel((1 << num_cores) - 1, cm_base + GCR_ACCESS); |
| 57 | |
| 58 | writel(GCR_REG0_BASE_VALUE, cm_base + GCR_REG0_BASE); |
| 59 | writel(GCR_REG1_BASE_VALUE, cm_base + GCR_REG1_BASE); |
| 60 | writel(GCR_REG2_BASE_VALUE, cm_base + GCR_REG2_BASE); |
| 61 | writel(GCR_REG3_BASE_VALUE, cm_base + GCR_REG3_BASE); |
| 62 | |
| 63 | clrsetbits_32(cm_base + GCR_REG0_MASK, |
| 64 | GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT, |
| 65 | FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG0_MASK_VALUE) | |
| 66 | GCR_REGn_MASK_CMTGT_IOCU0); |
| 67 | |
| 68 | clrsetbits_32(cm_base + GCR_REG1_MASK, |
| 69 | GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT, |
| 70 | FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG1_MASK_VALUE) | |
| 71 | GCR_REGn_MASK_CMTGT_IOCU0); |
| 72 | |
| 73 | clrsetbits_32(cm_base + GCR_REG2_MASK, |
| 74 | GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT, |
| 75 | FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG2_MASK_VALUE) | |
| 76 | GCR_REGn_MASK_CMTGT_IOCU0); |
| 77 | |
| 78 | clrsetbits_32(cm_base + GCR_REG3_MASK, |
| 79 | GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT, |
| 80 | FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG3_MASK_VALUE) | |
| 81 | GCR_REGn_MASK_CMTGT_IOCU0); |
| 82 | |
| 83 | clrbits_32(cm_base + GCR_BASE, CM_DEFAULT_TARGET_MASK); |
| 84 | setbits_32(cm_base + GCR_CONTROL, GCR_CONTROL_SYNCCTL); |
| 85 | } |
| 86 | |
| 87 | static void gic_init(void) |
| 88 | { |
| 89 | void __iomem *gic_base = (void *)KSEG1ADDR(MIPS_GIC_BASE); |
| 90 | int i; |
| 91 | |
| 92 | /* Interrupt 0..5: Level Trigger, Active High */ |
| 93 | writel(0, gic_base + GIC_SH_TRIG31_0); |
| 94 | writel(0x3f, gic_base + GIC_SH_RMASK31_0); |
| 95 | writel(0x3f, gic_base + GIC_SH_POL31_0); |
| 96 | writel(0x3f, gic_base + GIC_SH_SMASK31_0); |
| 97 | |
| 98 | /* Interrupt 56..63: Edge Trigger, Rising Edge */ |
| 99 | /* Hardcoded to set up the last 8 external interrupts for IPI. */ |
| 100 | writel(0xff000000, gic_base + GIC_SH_TRIG63_32); |
| 101 | writel(0xff000000, gic_base + GIC_SH_RMASK63_32); |
| 102 | writel(0xff000000, gic_base + GIC_SH_POL63_32); |
| 103 | writel(0xff000000, gic_base + GIC_SH_SMASK63_32); |
| 104 | |
| 105 | /* Map interrupt source to particular hardware interrupt pin */ |
| 106 | /* source {0,1,2,3,4,5} -> pin {0,0,4,3,0,5} */ |
| 107 | writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(0)); |
| 108 | writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(1)); |
| 109 | writel(GIC_MAP_TO_PIN | 4, gic_base + GIC_SH_MAP_PIN(2)); |
| 110 | writel(GIC_MAP_TO_PIN | 3, gic_base + GIC_SH_MAP_PIN(3)); |
| 111 | writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(4)); |
| 112 | writel(GIC_MAP_TO_PIN | 5, gic_base + GIC_SH_MAP_PIN(5)); |
| 113 | |
| 114 | /* source 56~59 -> pin 1, 60~63 -> pin 2 */ |
| 115 | writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(56)); |
| 116 | writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(57)); |
| 117 | writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(58)); |
| 118 | writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(59)); |
| 119 | writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(60)); |
| 120 | writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(61)); |
| 121 | writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(62)); |
| 122 | writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(63)); |
| 123 | |
| 124 | /* Interrupt map to VPE (bit mask) */ |
| 125 | for (i = 0; i < 32; i++) |
| 126 | writel(BIT(0), gic_base + GIC_SH_MAP_VPE31_0(i)); |
| 127 | |
| 128 | /* |
| 129 | * Direct GIC_int 56..63 to vpe 0..3 |
| 130 | * MIPS Linux convention that last 16 interrupts implemented be set |
| 131 | * aside for IPI signaling. |
| 132 | * The actual interrupts are tied low and software sends interrupts |
| 133 | * via GIC_SH_WEDGE writes. |
| 134 | */ |
| 135 | for (i = 0; i < 4; i++) { |
| 136 | writel(BIT(i), gic_base + GIC_SH_MAP_VPE31_0(i + 56)); |
| 137 | writel(BIT(i), gic_base + GIC_SH_MAP_VPE31_0(i + 60)); |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | void mt7621_cps_init(void) |
| 142 | { |
| 143 | void __iomem *cm_base = (void *)KSEG1ADDR(CONFIG_MIPS_CM_BASE); |
| 144 | |
| 145 | /* Enable GIC */ |
| 146 | writel(MIPS_GIC_BASE | GCR_GIC_EN, cm_base + GCR_GIC_BASE); |
| 147 | |
| 148 | /* Enable CPC */ |
| 149 | writel(MIPS_CPC_BASE | GCR_CPC_EN, cm_base + GCR_CPC_BASE); |
| 150 | |
| 151 | gic_init(); |
| 152 | cm_init(cm_base); |
| 153 | } |