1 | /* |
2 | * QEMU PowerPC PowerNV LPC controller |
3 | * |
4 | * Copyright (c) 2016, IBM Corporation. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | #include "qemu/osdep.h" |
21 | #include "target/ppc/cpu.h" |
22 | #include "qapi/error.h" |
23 | #include "qemu/log.h" |
24 | #include "qemu/module.h" |
25 | #include "hw/irq.h" |
26 | #include "hw/isa/isa.h" |
27 | |
28 | #include "hw/ppc/pnv.h" |
29 | #include "hw/ppc/pnv_lpc.h" |
30 | #include "hw/ppc/pnv_xscom.h" |
31 | #include "hw/ppc/fdt.h" |
32 | |
33 | #include <libfdt.h> |
34 | |
35 | enum { |
36 | ECCB_CTL = 0, |
37 | ECCB_RESET = 1, |
38 | ECCB_STAT = 2, |
39 | ECCB_DATA = 3, |
40 | }; |
41 | |
42 | /* OPB Master LS registers */ |
43 | #define OPB_MASTER_LS_ROUTE0 0x8 |
44 | #define OPB_MASTER_LS_ROUTE1 0xC |
45 | #define OPB_MASTER_LS_IRQ_STAT 0x50 |
46 | #define OPB_MASTER_IRQ_LPC 0x00000800 |
47 | #define OPB_MASTER_LS_IRQ_MASK 0x54 |
48 | #define OPB_MASTER_LS_IRQ_POL 0x58 |
49 | #define OPB_MASTER_LS_IRQ_INPUT 0x5c |
50 | |
51 | /* LPC HC registers */ |
52 | #define LPC_HC_FW_SEG_IDSEL 0x24 |
53 | #define LPC_HC_FW_RD_ACC_SIZE 0x28 |
54 | #define LPC_HC_FW_RD_1B 0x00000000 |
55 | #define LPC_HC_FW_RD_2B 0x01000000 |
56 | #define LPC_HC_FW_RD_4B 0x02000000 |
57 | #define LPC_HC_FW_RD_16B 0x04000000 |
58 | #define LPC_HC_FW_RD_128B 0x07000000 |
59 | #define LPC_HC_IRQSER_CTRL 0x30 |
60 | #define LPC_HC_IRQSER_EN 0x80000000 |
61 | #define LPC_HC_IRQSER_QMODE 0x40000000 |
62 | #define LPC_HC_IRQSER_START_MASK 0x03000000 |
63 | #define LPC_HC_IRQSER_START_4CLK 0x00000000 |
64 | #define LPC_HC_IRQSER_START_6CLK 0x01000000 |
65 | #define LPC_HC_IRQSER_START_8CLK 0x02000000 |
66 | #define LPC_HC_IRQMASK 0x34 /* same bit defs as LPC_HC_IRQSTAT */ |
67 | #define LPC_HC_IRQSTAT 0x38 |
68 | #define LPC_HC_IRQ_SERIRQ0 0x80000000 /* all bits down to ... */ |
69 | #define LPC_HC_IRQ_SERIRQ16 0x00008000 /* IRQ16=IOCHK#, IRQ2=SMI# */ |
70 | #define LPC_HC_IRQ_SERIRQ_ALL 0xffff8000 |
71 | #define LPC_HC_IRQ_LRESET 0x00000400 |
72 | #define LPC_HC_IRQ_SYNC_ABNORM_ERR 0x00000080 |
73 | #define LPC_HC_IRQ_SYNC_NORESP_ERR 0x00000040 |
74 | #define LPC_HC_IRQ_SYNC_NORM_ERR 0x00000020 |
75 | #define LPC_HC_IRQ_SYNC_TIMEOUT_ERR 0x00000010 |
76 | #define LPC_HC_IRQ_SYNC_TARG_TAR_ERR 0x00000008 |
77 | #define LPC_HC_IRQ_SYNC_BM_TAR_ERR 0x00000004 |
78 | #define LPC_HC_IRQ_SYNC_BM0_REQ 0x00000002 |
79 | #define LPC_HC_IRQ_SYNC_BM1_REQ 0x00000001 |
80 | #define LPC_HC_ERROR_ADDRESS 0x40 |
81 | |
82 | #define LPC_OPB_SIZE 0x100000000ull |
83 | |
84 | #define ISA_IO_SIZE 0x00010000 |
85 | #define ISA_MEM_SIZE 0x10000000 |
86 | #define ISA_FW_SIZE 0x10000000 |
87 | #define LPC_IO_OPB_ADDR 0xd0010000 |
88 | #define LPC_IO_OPB_SIZE 0x00010000 |
89 | #define LPC_MEM_OPB_ADDR 0xe0010000 |
90 | #define LPC_MEM_OPB_SIZE 0x10000000 |
91 | #define LPC_FW_OPB_ADDR 0xf0000000 |
92 | #define LPC_FW_OPB_SIZE 0x10000000 |
93 | |
94 | #define LPC_OPB_REGS_OPB_ADDR 0xc0010000 |
95 | #define LPC_OPB_REGS_OPB_SIZE 0x00000060 |
96 | #define LPC_OPB_REGS_OPBA_ADDR 0xc0011000 |
97 | #define LPC_OPB_REGS_OPBA_SIZE 0x00000008 |
98 | #define LPC_HC_REGS_OPB_ADDR 0xc0012000 |
99 | #define LPC_HC_REGS_OPB_SIZE 0x00000100 |
100 | |
101 | static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset) |
102 | { |
103 | const char compat[] = "ibm,power8-lpc\0ibm,lpc" ; |
104 | char *name; |
105 | int offset; |
106 | uint32_t lpc_pcba = PNV_XSCOM_LPC_BASE; |
107 | uint32_t reg[] = { |
108 | cpu_to_be32(lpc_pcba), |
109 | cpu_to_be32(PNV_XSCOM_LPC_SIZE) |
110 | }; |
111 | |
112 | name = g_strdup_printf("isa@%x" , lpc_pcba); |
113 | offset = fdt_add_subnode(fdt, xscom_offset, name); |
114 | _FDT(offset); |
115 | g_free(name); |
116 | |
117 | _FDT((fdt_setprop(fdt, offset, "reg" , reg, sizeof(reg)))); |
118 | _FDT((fdt_setprop_cell(fdt, offset, "#address-cells" , 2))); |
119 | _FDT((fdt_setprop_cell(fdt, offset, "#size-cells" , 1))); |
120 | _FDT((fdt_setprop(fdt, offset, "compatible" , compat, sizeof(compat)))); |
121 | return 0; |
122 | } |
123 | |
124 | /* POWER9 only */ |
125 | int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset) |
126 | { |
127 | const char compat[] = "ibm,power9-lpcm-opb\0simple-bus" ; |
128 | const char lpc_compat[] = "ibm,power9-lpc\0ibm,lpc" ; |
129 | char *name; |
130 | int offset, lpcm_offset; |
131 | uint64_t lpcm_addr = PNV9_LPCM_BASE(chip); |
132 | uint32_t opb_ranges[8] = { 0, |
133 | cpu_to_be32(lpcm_addr >> 32), |
134 | cpu_to_be32((uint32_t)lpcm_addr), |
135 | cpu_to_be32(PNV9_LPCM_SIZE / 2), |
136 | cpu_to_be32(PNV9_LPCM_SIZE / 2), |
137 | cpu_to_be32(lpcm_addr >> 32), |
138 | cpu_to_be32(PNV9_LPCM_SIZE / 2), |
139 | cpu_to_be32(PNV9_LPCM_SIZE / 2), |
140 | }; |
141 | uint32_t opb_reg[4] = { cpu_to_be32(lpcm_addr >> 32), |
142 | cpu_to_be32((uint32_t)lpcm_addr), |
143 | cpu_to_be32(PNV9_LPCM_SIZE >> 32), |
144 | cpu_to_be32((uint32_t)PNV9_LPCM_SIZE), |
145 | }; |
146 | uint32_t reg[2]; |
147 | |
148 | /* |
149 | * OPB bus |
150 | */ |
151 | name = g_strdup_printf("lpcm-opb@%" PRIx64, lpcm_addr); |
152 | lpcm_offset = fdt_add_subnode(fdt, root_offset, name); |
153 | _FDT(lpcm_offset); |
154 | g_free(name); |
155 | |
156 | _FDT((fdt_setprop(fdt, lpcm_offset, "reg" , opb_reg, sizeof(opb_reg)))); |
157 | _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#address-cells" , 1))); |
158 | _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#size-cells" , 1))); |
159 | _FDT((fdt_setprop(fdt, lpcm_offset, "compatible" , compat, sizeof(compat)))); |
160 | _FDT((fdt_setprop_cell(fdt, lpcm_offset, "ibm,chip-id" , chip->chip_id))); |
161 | _FDT((fdt_setprop(fdt, lpcm_offset, "ranges" , opb_ranges, |
162 | sizeof(opb_ranges)))); |
163 | |
164 | /* |
165 | * OPB Master registers |
166 | */ |
167 | name = g_strdup_printf("opb-master@%x" , LPC_OPB_REGS_OPB_ADDR); |
168 | offset = fdt_add_subnode(fdt, lpcm_offset, name); |
169 | _FDT(offset); |
170 | g_free(name); |
171 | |
172 | reg[0] = cpu_to_be32(LPC_OPB_REGS_OPB_ADDR); |
173 | reg[1] = cpu_to_be32(LPC_OPB_REGS_OPB_SIZE); |
174 | _FDT((fdt_setprop(fdt, offset, "reg" , reg, sizeof(reg)))); |
175 | _FDT((fdt_setprop_string(fdt, offset, "compatible" , |
176 | "ibm,power9-lpcm-opb-master" ))); |
177 | |
178 | /* |
179 | * OPB arbitrer registers |
180 | */ |
181 | name = g_strdup_printf("opb-arbitrer@%x" , LPC_OPB_REGS_OPBA_ADDR); |
182 | offset = fdt_add_subnode(fdt, lpcm_offset, name); |
183 | _FDT(offset); |
184 | g_free(name); |
185 | |
186 | reg[0] = cpu_to_be32(LPC_OPB_REGS_OPBA_ADDR); |
187 | reg[1] = cpu_to_be32(LPC_OPB_REGS_OPBA_SIZE); |
188 | _FDT((fdt_setprop(fdt, offset, "reg" , reg, sizeof(reg)))); |
189 | _FDT((fdt_setprop_string(fdt, offset, "compatible" , |
190 | "ibm,power9-lpcm-opb-arbiter" ))); |
191 | |
192 | /* |
193 | * LPC Host Controller registers |
194 | */ |
195 | name = g_strdup_printf("lpc-controller@%x" , LPC_HC_REGS_OPB_ADDR); |
196 | offset = fdt_add_subnode(fdt, lpcm_offset, name); |
197 | _FDT(offset); |
198 | g_free(name); |
199 | |
200 | reg[0] = cpu_to_be32(LPC_HC_REGS_OPB_ADDR); |
201 | reg[1] = cpu_to_be32(LPC_HC_REGS_OPB_SIZE); |
202 | _FDT((fdt_setprop(fdt, offset, "reg" , reg, sizeof(reg)))); |
203 | _FDT((fdt_setprop_string(fdt, offset, "compatible" , |
204 | "ibm,power9-lpc-controller" ))); |
205 | |
206 | name = g_strdup_printf("lpc@0" ); |
207 | offset = fdt_add_subnode(fdt, lpcm_offset, name); |
208 | _FDT(offset); |
209 | g_free(name); |
210 | _FDT((fdt_setprop_cell(fdt, offset, "#address-cells" , 2))); |
211 | _FDT((fdt_setprop_cell(fdt, offset, "#size-cells" , 1))); |
212 | _FDT((fdt_setprop(fdt, offset, "compatible" , lpc_compat, |
213 | sizeof(lpc_compat)))); |
214 | |
215 | return 0; |
216 | } |
217 | |
218 | /* |
219 | * These read/write handlers of the OPB address space should be common |
220 | * with the P9 LPC Controller which uses direct MMIOs. |
221 | * |
222 | * TODO: rework to use address_space_stq() and address_space_ldq() |
223 | * instead. |
224 | */ |
225 | static bool opb_read(PnvLpcController *lpc, uint32_t addr, uint8_t *data, |
226 | int sz) |
227 | { |
228 | /* XXX Handle access size limits and FW read caching here */ |
229 | return !address_space_rw(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED, |
230 | data, sz, false); |
231 | } |
232 | |
233 | static bool opb_write(PnvLpcController *lpc, uint32_t addr, uint8_t *data, |
234 | int sz) |
235 | { |
236 | /* XXX Handle access size limits here */ |
237 | return !address_space_rw(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED, |
238 | data, sz, true); |
239 | } |
240 | |
241 | #define ECCB_CTL_READ PPC_BIT(15) |
242 | #define ECCB_CTL_SZ_LSH (63 - 7) |
243 | #define ECCB_CTL_SZ_MASK PPC_BITMASK(4, 7) |
244 | #define ECCB_CTL_ADDR_MASK PPC_BITMASK(32, 63) |
245 | |
246 | #define ECCB_STAT_OP_DONE PPC_BIT(52) |
247 | #define ECCB_STAT_OP_ERR PPC_BIT(52) |
248 | #define ECCB_STAT_RD_DATA_LSH (63 - 37) |
249 | #define ECCB_STAT_RD_DATA_MASK (0xffffffff << ECCB_STAT_RD_DATA_LSH) |
250 | |
251 | static void pnv_lpc_do_eccb(PnvLpcController *lpc, uint64_t cmd) |
252 | { |
253 | /* XXX Check for magic bits at the top, addr size etc... */ |
254 | unsigned int sz = (cmd & ECCB_CTL_SZ_MASK) >> ECCB_CTL_SZ_LSH; |
255 | uint32_t opb_addr = cmd & ECCB_CTL_ADDR_MASK; |
256 | uint8_t data[8]; |
257 | bool success; |
258 | |
259 | if (sz > sizeof(data)) { |
260 | qemu_log_mask(LOG_GUEST_ERROR, |
261 | "ECCB: invalid operation at @0x%08x size %d\n" , opb_addr, sz); |
262 | return; |
263 | } |
264 | |
265 | if (cmd & ECCB_CTL_READ) { |
266 | success = opb_read(lpc, opb_addr, data, sz); |
267 | if (success) { |
268 | lpc->eccb_stat_reg = ECCB_STAT_OP_DONE | |
269 | (((uint64_t)data[0]) << 24 | |
270 | ((uint64_t)data[1]) << 16 | |
271 | ((uint64_t)data[2]) << 8 | |
272 | ((uint64_t)data[3])) << ECCB_STAT_RD_DATA_LSH; |
273 | } else { |
274 | lpc->eccb_stat_reg = ECCB_STAT_OP_DONE | |
275 | (0xffffffffull << ECCB_STAT_RD_DATA_LSH); |
276 | } |
277 | } else { |
278 | data[0] = lpc->eccb_data_reg >> 24; |
279 | data[1] = lpc->eccb_data_reg >> 16; |
280 | data[2] = lpc->eccb_data_reg >> 8; |
281 | data[3] = lpc->eccb_data_reg; |
282 | |
283 | success = opb_write(lpc, opb_addr, data, sz); |
284 | lpc->eccb_stat_reg = ECCB_STAT_OP_DONE; |
285 | } |
286 | /* XXX Which error bit (if any) to signal OPB error ? */ |
287 | } |
288 | |
289 | static uint64_t pnv_lpc_xscom_read(void *opaque, hwaddr addr, unsigned size) |
290 | { |
291 | PnvLpcController *lpc = PNV_LPC(opaque); |
292 | uint32_t offset = addr >> 3; |
293 | uint64_t val = 0; |
294 | |
295 | switch (offset & 3) { |
296 | case ECCB_CTL: |
297 | case ECCB_RESET: |
298 | val = 0; |
299 | break; |
300 | case ECCB_STAT: |
301 | val = lpc->eccb_stat_reg; |
302 | lpc->eccb_stat_reg = 0; |
303 | break; |
304 | case ECCB_DATA: |
305 | val = ((uint64_t)lpc->eccb_data_reg) << 32; |
306 | break; |
307 | } |
308 | return val; |
309 | } |
310 | |
311 | static void pnv_lpc_xscom_write(void *opaque, hwaddr addr, |
312 | uint64_t val, unsigned size) |
313 | { |
314 | PnvLpcController *lpc = PNV_LPC(opaque); |
315 | uint32_t offset = addr >> 3; |
316 | |
317 | switch (offset & 3) { |
318 | case ECCB_CTL: |
319 | pnv_lpc_do_eccb(lpc, val); |
320 | break; |
321 | case ECCB_RESET: |
322 | /* XXXX */ |
323 | break; |
324 | case ECCB_STAT: |
325 | break; |
326 | case ECCB_DATA: |
327 | lpc->eccb_data_reg = val >> 32; |
328 | break; |
329 | } |
330 | } |
331 | |
332 | static const MemoryRegionOps pnv_lpc_xscom_ops = { |
333 | .read = pnv_lpc_xscom_read, |
334 | .write = pnv_lpc_xscom_write, |
335 | .valid.min_access_size = 8, |
336 | .valid.max_access_size = 8, |
337 | .impl.min_access_size = 8, |
338 | .impl.max_access_size = 8, |
339 | .endianness = DEVICE_BIG_ENDIAN, |
340 | }; |
341 | |
342 | static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size) |
343 | { |
344 | PnvLpcController *lpc = PNV_LPC(opaque); |
345 | uint64_t val = 0; |
346 | uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK; |
347 | MemTxResult result; |
348 | |
349 | switch (size) { |
350 | case 4: |
351 | val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED, |
352 | &result); |
353 | break; |
354 | case 1: |
355 | val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED, |
356 | &result); |
357 | break; |
358 | default: |
359 | qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%" |
360 | HWADDR_PRIx " invalid size %d\n" , addr, size); |
361 | return 0; |
362 | } |
363 | |
364 | if (result != MEMTX_OK) { |
365 | qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%" |
366 | HWADDR_PRIx "\n" , addr); |
367 | } |
368 | |
369 | return val; |
370 | } |
371 | |
372 | static void pnv_lpc_mmio_write(void *opaque, hwaddr addr, |
373 | uint64_t val, unsigned size) |
374 | { |
375 | PnvLpcController *lpc = PNV_LPC(opaque); |
376 | uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK; |
377 | MemTxResult result; |
378 | |
379 | switch (size) { |
380 | case 4: |
381 | address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED, |
382 | &result); |
383 | break; |
384 | case 1: |
385 | address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED, |
386 | &result); |
387 | break; |
388 | default: |
389 | qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%" |
390 | HWADDR_PRIx " invalid size %d\n" , addr, size); |
391 | return; |
392 | } |
393 | |
394 | if (result != MEMTX_OK) { |
395 | qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%" |
396 | HWADDR_PRIx "\n" , addr); |
397 | } |
398 | } |
399 | |
400 | static const MemoryRegionOps pnv_lpc_mmio_ops = { |
401 | .read = pnv_lpc_mmio_read, |
402 | .write = pnv_lpc_mmio_write, |
403 | .impl = { |
404 | .min_access_size = 1, |
405 | .max_access_size = 4, |
406 | }, |
407 | .endianness = DEVICE_BIG_ENDIAN, |
408 | }; |
409 | |
410 | static void pnv_lpc_eval_irqs(PnvLpcController *lpc) |
411 | { |
412 | bool lpc_to_opb_irq = false; |
413 | PnvLpcClass *plc = PNV_LPC_GET_CLASS(lpc); |
414 | |
415 | /* Update LPC controller to OPB line */ |
416 | if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) { |
417 | uint32_t irqs; |
418 | |
419 | irqs = lpc->lpc_hc_irqstat & lpc->lpc_hc_irqmask; |
420 | lpc_to_opb_irq = (irqs != 0); |
421 | } |
422 | |
423 | /* We don't honor the polarity register, it's pointless and unused |
424 | * anyway |
425 | */ |
426 | if (lpc_to_opb_irq) { |
427 | lpc->opb_irq_input |= OPB_MASTER_IRQ_LPC; |
428 | } else { |
429 | lpc->opb_irq_input &= ~OPB_MASTER_IRQ_LPC; |
430 | } |
431 | |
432 | /* Update OPB internal latch */ |
433 | lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask; |
434 | |
435 | /* Reflect the interrupt */ |
436 | pnv_psi_irq_set(lpc->psi, plc->psi_irq, lpc->opb_irq_stat != 0); |
437 | } |
438 | |
439 | static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size) |
440 | { |
441 | PnvLpcController *lpc = opaque; |
442 | uint64_t val = 0xfffffffffffffffful; |
443 | |
444 | switch (addr) { |
445 | case LPC_HC_FW_SEG_IDSEL: |
446 | val = lpc->lpc_hc_fw_seg_idsel; |
447 | break; |
448 | case LPC_HC_FW_RD_ACC_SIZE: |
449 | val = lpc->lpc_hc_fw_rd_acc_size; |
450 | break; |
451 | case LPC_HC_IRQSER_CTRL: |
452 | val = lpc->lpc_hc_irqser_ctrl; |
453 | break; |
454 | case LPC_HC_IRQMASK: |
455 | val = lpc->lpc_hc_irqmask; |
456 | break; |
457 | case LPC_HC_IRQSTAT: |
458 | val = lpc->lpc_hc_irqstat; |
459 | break; |
460 | case LPC_HC_ERROR_ADDRESS: |
461 | val = lpc->lpc_hc_error_addr; |
462 | break; |
463 | default: |
464 | qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%" |
465 | HWADDR_PRIx "\n" , addr); |
466 | } |
467 | return val; |
468 | } |
469 | |
470 | static void lpc_hc_write(void *opaque, hwaddr addr, uint64_t val, |
471 | unsigned size) |
472 | { |
473 | PnvLpcController *lpc = opaque; |
474 | |
475 | /* XXX Filter out reserved bits */ |
476 | |
477 | switch (addr) { |
478 | case LPC_HC_FW_SEG_IDSEL: |
479 | /* XXX Actually figure out how that works as this impact |
480 | * memory regions/aliases |
481 | */ |
482 | lpc->lpc_hc_fw_seg_idsel = val; |
483 | break; |
484 | case LPC_HC_FW_RD_ACC_SIZE: |
485 | lpc->lpc_hc_fw_rd_acc_size = val; |
486 | break; |
487 | case LPC_HC_IRQSER_CTRL: |
488 | lpc->lpc_hc_irqser_ctrl = val; |
489 | pnv_lpc_eval_irqs(lpc); |
490 | break; |
491 | case LPC_HC_IRQMASK: |
492 | lpc->lpc_hc_irqmask = val; |
493 | pnv_lpc_eval_irqs(lpc); |
494 | break; |
495 | case LPC_HC_IRQSTAT: |
496 | lpc->lpc_hc_irqstat &= ~val; |
497 | pnv_lpc_eval_irqs(lpc); |
498 | break; |
499 | case LPC_HC_ERROR_ADDRESS: |
500 | break; |
501 | default: |
502 | qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%" |
503 | HWADDR_PRIx "\n" , addr); |
504 | } |
505 | } |
506 | |
507 | static const MemoryRegionOps lpc_hc_ops = { |
508 | .read = lpc_hc_read, |
509 | .write = lpc_hc_write, |
510 | .endianness = DEVICE_BIG_ENDIAN, |
511 | .valid = { |
512 | .min_access_size = 4, |
513 | .max_access_size = 4, |
514 | }, |
515 | .impl = { |
516 | .min_access_size = 4, |
517 | .max_access_size = 4, |
518 | }, |
519 | }; |
520 | |
521 | static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size) |
522 | { |
523 | PnvLpcController *lpc = opaque; |
524 | uint64_t val = 0xfffffffffffffffful; |
525 | |
526 | switch (addr) { |
527 | case OPB_MASTER_LS_ROUTE0: /* TODO */ |
528 | val = lpc->opb_irq_route0; |
529 | break; |
530 | case OPB_MASTER_LS_ROUTE1: /* TODO */ |
531 | val = lpc->opb_irq_route1; |
532 | break; |
533 | case OPB_MASTER_LS_IRQ_STAT: |
534 | val = lpc->opb_irq_stat; |
535 | break; |
536 | case OPB_MASTER_LS_IRQ_MASK: |
537 | val = lpc->opb_irq_mask; |
538 | break; |
539 | case OPB_MASTER_LS_IRQ_POL: |
540 | val = lpc->opb_irq_pol; |
541 | break; |
542 | case OPB_MASTER_LS_IRQ_INPUT: |
543 | val = lpc->opb_irq_input; |
544 | break; |
545 | default: |
546 | qemu_log_mask(LOG_UNIMP, "OPBM: read on unimplemented register: 0x%" |
547 | HWADDR_PRIx "\n" , addr); |
548 | } |
549 | |
550 | return val; |
551 | } |
552 | |
553 | static void opb_master_write(void *opaque, hwaddr addr, |
554 | uint64_t val, unsigned size) |
555 | { |
556 | PnvLpcController *lpc = opaque; |
557 | |
558 | switch (addr) { |
559 | case OPB_MASTER_LS_ROUTE0: /* TODO */ |
560 | lpc->opb_irq_route0 = val; |
561 | break; |
562 | case OPB_MASTER_LS_ROUTE1: /* TODO */ |
563 | lpc->opb_irq_route1 = val; |
564 | break; |
565 | case OPB_MASTER_LS_IRQ_STAT: |
566 | lpc->opb_irq_stat &= ~val; |
567 | pnv_lpc_eval_irqs(lpc); |
568 | break; |
569 | case OPB_MASTER_LS_IRQ_MASK: |
570 | lpc->opb_irq_mask = val; |
571 | pnv_lpc_eval_irqs(lpc); |
572 | break; |
573 | case OPB_MASTER_LS_IRQ_POL: |
574 | lpc->opb_irq_pol = val; |
575 | pnv_lpc_eval_irqs(lpc); |
576 | break; |
577 | case OPB_MASTER_LS_IRQ_INPUT: |
578 | /* Read only */ |
579 | break; |
580 | default: |
581 | qemu_log_mask(LOG_UNIMP, "OPBM: write on unimplemented register: 0x%" |
582 | HWADDR_PRIx " val=0x%08" PRIx64"\n" , addr, val); |
583 | } |
584 | } |
585 | |
586 | static const MemoryRegionOps opb_master_ops = { |
587 | .read = opb_master_read, |
588 | .write = opb_master_write, |
589 | .endianness = DEVICE_BIG_ENDIAN, |
590 | .valid = { |
591 | .min_access_size = 4, |
592 | .max_access_size = 4, |
593 | }, |
594 | .impl = { |
595 | .min_access_size = 4, |
596 | .max_access_size = 4, |
597 | }, |
598 | }; |
599 | |
600 | static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp) |
601 | { |
602 | PnvLpcController *lpc = PNV_LPC(dev); |
603 | PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev); |
604 | Error *local_err = NULL; |
605 | |
606 | plc->parent_realize(dev, &local_err); |
607 | if (local_err) { |
608 | error_propagate(errp, local_err); |
609 | return; |
610 | } |
611 | |
612 | /* P8 uses a XSCOM region for LPC registers */ |
613 | pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(lpc), |
614 | &pnv_lpc_xscom_ops, lpc, "xscom-lpc" , |
615 | PNV_XSCOM_LPC_SIZE); |
616 | } |
617 | |
618 | static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data) |
619 | { |
620 | DeviceClass *dc = DEVICE_CLASS(klass); |
621 | PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); |
622 | PnvLpcClass *plc = PNV_LPC_CLASS(klass); |
623 | |
624 | dc->desc = "PowerNV LPC Controller POWER8" ; |
625 | |
626 | xdc->dt_xscom = pnv_lpc_dt_xscom; |
627 | |
628 | plc->psi_irq = PSIHB_IRQ_LPC_I2C; |
629 | |
630 | device_class_set_parent_realize(dc, pnv_lpc_power8_realize, |
631 | &plc->parent_realize); |
632 | } |
633 | |
634 | static const TypeInfo pnv_lpc_power8_info = { |
635 | .name = TYPE_PNV8_LPC, |
636 | .parent = TYPE_PNV_LPC, |
637 | .instance_size = sizeof(PnvLpcController), |
638 | .class_init = pnv_lpc_power8_class_init, |
639 | .interfaces = (InterfaceInfo[]) { |
640 | { TYPE_PNV_XSCOM_INTERFACE }, |
641 | { } |
642 | } |
643 | }; |
644 | |
645 | static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp) |
646 | { |
647 | PnvLpcController *lpc = PNV_LPC(dev); |
648 | PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev); |
649 | Error *local_err = NULL; |
650 | |
651 | plc->parent_realize(dev, &local_err); |
652 | if (local_err) { |
653 | error_propagate(errp, local_err); |
654 | return; |
655 | } |
656 | |
657 | /* P9 uses a MMIO region */ |
658 | memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops, |
659 | lpc, "lpcm" , PNV9_LPCM_SIZE); |
660 | } |
661 | |
662 | static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data) |
663 | { |
664 | DeviceClass *dc = DEVICE_CLASS(klass); |
665 | PnvLpcClass *plc = PNV_LPC_CLASS(klass); |
666 | |
667 | dc->desc = "PowerNV LPC Controller POWER9" ; |
668 | |
669 | plc->psi_irq = PSIHB9_IRQ_LPCHC; |
670 | |
671 | device_class_set_parent_realize(dc, pnv_lpc_power9_realize, |
672 | &plc->parent_realize); |
673 | } |
674 | |
675 | static const TypeInfo pnv_lpc_power9_info = { |
676 | .name = TYPE_PNV9_LPC, |
677 | .parent = TYPE_PNV_LPC, |
678 | .instance_size = sizeof(PnvLpcController), |
679 | .class_init = pnv_lpc_power9_class_init, |
680 | }; |
681 | |
682 | static void pnv_lpc_realize(DeviceState *dev, Error **errp) |
683 | { |
684 | PnvLpcController *lpc = PNV_LPC(dev); |
685 | Object *obj; |
686 | Error *local_err = NULL; |
687 | |
688 | obj = object_property_get_link(OBJECT(dev), "psi" , &local_err); |
689 | if (!obj) { |
690 | error_propagate(errp, local_err); |
691 | error_prepend(errp, "required link 'psi' not found: " ); |
692 | return; |
693 | } |
694 | /* The LPC controller needs PSI to generate interrupts */ |
695 | lpc->psi = PNV_PSI(obj); |
696 | |
697 | /* Reg inits */ |
698 | lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B; |
699 | |
700 | /* Create address space and backing MR for the OPB bus */ |
701 | memory_region_init(&lpc->opb_mr, OBJECT(dev), "lpc-opb" , 0x100000000ull); |
702 | address_space_init(&lpc->opb_as, &lpc->opb_mr, "lpc-opb" ); |
703 | |
704 | /* Create ISA IO and Mem space regions which are the root of |
705 | * the ISA bus (ie, ISA address spaces). We don't create a |
706 | * separate one for FW which we alias to memory. |
707 | */ |
708 | memory_region_init(&lpc->isa_io, OBJECT(dev), "isa-io" , ISA_IO_SIZE); |
709 | memory_region_init(&lpc->isa_mem, OBJECT(dev), "isa-mem" , ISA_MEM_SIZE); |
710 | memory_region_init(&lpc->isa_fw, OBJECT(dev), "isa-fw" , ISA_FW_SIZE); |
711 | |
712 | /* Create windows from the OPB space to the ISA space */ |
713 | memory_region_init_alias(&lpc->opb_isa_io, OBJECT(dev), "lpc-isa-io" , |
714 | &lpc->isa_io, 0, LPC_IO_OPB_SIZE); |
715 | memory_region_add_subregion(&lpc->opb_mr, LPC_IO_OPB_ADDR, |
716 | &lpc->opb_isa_io); |
717 | memory_region_init_alias(&lpc->opb_isa_mem, OBJECT(dev), "lpc-isa-mem" , |
718 | &lpc->isa_mem, 0, LPC_MEM_OPB_SIZE); |
719 | memory_region_add_subregion(&lpc->opb_mr, LPC_MEM_OPB_ADDR, |
720 | &lpc->opb_isa_mem); |
721 | memory_region_init_alias(&lpc->opb_isa_fw, OBJECT(dev), "lpc-isa-fw" , |
722 | &lpc->isa_fw, 0, LPC_FW_OPB_SIZE); |
723 | memory_region_add_subregion(&lpc->opb_mr, LPC_FW_OPB_ADDR, |
724 | &lpc->opb_isa_fw); |
725 | |
726 | /* Create MMIO regions for LPC HC and OPB registers */ |
727 | memory_region_init_io(&lpc->opb_master_regs, OBJECT(dev), &opb_master_ops, |
728 | lpc, "lpc-opb-master" , LPC_OPB_REGS_OPB_SIZE); |
729 | memory_region_add_subregion(&lpc->opb_mr, LPC_OPB_REGS_OPB_ADDR, |
730 | &lpc->opb_master_regs); |
731 | memory_region_init_io(&lpc->lpc_hc_regs, OBJECT(dev), &lpc_hc_ops, lpc, |
732 | "lpc-hc" , LPC_HC_REGS_OPB_SIZE); |
733 | memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR, |
734 | &lpc->lpc_hc_regs); |
735 | } |
736 | |
737 | static void pnv_lpc_class_init(ObjectClass *klass, void *data) |
738 | { |
739 | DeviceClass *dc = DEVICE_CLASS(klass); |
740 | |
741 | dc->realize = pnv_lpc_realize; |
742 | dc->desc = "PowerNV LPC Controller" ; |
743 | } |
744 | |
745 | static const TypeInfo pnv_lpc_info = { |
746 | .name = TYPE_PNV_LPC, |
747 | .parent = TYPE_DEVICE, |
748 | .class_init = pnv_lpc_class_init, |
749 | .class_size = sizeof(PnvLpcClass), |
750 | .abstract = true, |
751 | }; |
752 | |
753 | static void pnv_lpc_register_types(void) |
754 | { |
755 | type_register_static(&pnv_lpc_info); |
756 | type_register_static(&pnv_lpc_power8_info); |
757 | type_register_static(&pnv_lpc_power9_info); |
758 | } |
759 | |
760 | type_init(pnv_lpc_register_types) |
761 | |
762 | /* If we don't use the built-in LPC interrupt deserializer, we need |
763 | * to provide a set of qirqs for the ISA bus or things will go bad. |
764 | * |
765 | * Most machines using pre-Naples chips (without said deserializer) |
766 | * have a CPLD that will collect the SerIRQ and shoot them as a |
767 | * single level interrupt to the P8 chip. So let's setup a hook |
768 | * for doing just that. |
769 | */ |
770 | static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level) |
771 | { |
772 | PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); |
773 | uint32_t old_state = pnv->cpld_irqstate; |
774 | PnvLpcController *lpc = PNV_LPC(opaque); |
775 | |
776 | if (level) { |
777 | pnv->cpld_irqstate |= 1u << n; |
778 | } else { |
779 | pnv->cpld_irqstate &= ~(1u << n); |
780 | } |
781 | |
782 | if (pnv->cpld_irqstate != old_state) { |
783 | pnv_psi_irq_set(lpc->psi, PSIHB_IRQ_EXTERNAL, pnv->cpld_irqstate != 0); |
784 | } |
785 | } |
786 | |
787 | static void pnv_lpc_isa_irq_handler(void *opaque, int n, int level) |
788 | { |
789 | PnvLpcController *lpc = PNV_LPC(opaque); |
790 | |
791 | /* The Naples HW latches the 1 levels, clearing is done by SW */ |
792 | if (level) { |
793 | lpc->lpc_hc_irqstat |= LPC_HC_IRQ_SERIRQ0 >> n; |
794 | pnv_lpc_eval_irqs(lpc); |
795 | } |
796 | } |
797 | |
798 | ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp) |
799 | { |
800 | Error *local_err = NULL; |
801 | ISABus *isa_bus; |
802 | qemu_irq *irqs; |
803 | qemu_irq_handler handler; |
804 | |
805 | /* let isa_bus_new() create its own bridge on SysBus otherwise |
806 | * devices speficied on the command line won't find the bus and |
807 | * will fail to create. |
808 | */ |
809 | isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io, &local_err); |
810 | if (local_err) { |
811 | error_propagate(errp, local_err); |
812 | return NULL; |
813 | } |
814 | |
815 | /* Not all variants have a working serial irq decoder. If not, |
816 | * handling of LPC interrupts becomes a platform issue (some |
817 | * platforms have a CPLD to do it). |
818 | */ |
819 | if (use_cpld) { |
820 | handler = pnv_lpc_isa_irq_handler_cpld; |
821 | } else { |
822 | handler = pnv_lpc_isa_irq_handler; |
823 | } |
824 | |
825 | irqs = qemu_allocate_irqs(handler, lpc, ISA_NUM_IRQS); |
826 | |
827 | isa_bus_irqs(isa_bus, irqs); |
828 | return isa_bus; |
829 | } |
830 | |