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