.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2014-2017 Broadcom |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License version 2 as |
---|
6 | | - * published by the Free Software Foundation. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope that it will be useful, |
---|
9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
11 | | - * GNU General Public License for more details. |
---|
12 | 4 | */ |
---|
13 | 5 | |
---|
14 | 6 | #include <linux/init.h> |
---|
.. | .. |
---|
38 | 30 | #define ARB_ERR_CAP_STATUS_WRITE (1 << 1) |
---|
39 | 31 | #define ARB_ERR_CAP_STATUS_VALID (1 << 0) |
---|
40 | 32 | |
---|
| 33 | +#define ARB_BP_CAP_CLEAR (1 << 0) |
---|
| 34 | +#define ARB_BP_CAP_STATUS_PROT_SHIFT 14 |
---|
| 35 | +#define ARB_BP_CAP_STATUS_TYPE (1 << 13) |
---|
| 36 | +#define ARB_BP_CAP_STATUS_RSP_SHIFT 10 |
---|
| 37 | +#define ARB_BP_CAP_STATUS_MASK GENMASK(1, 0) |
---|
| 38 | +#define ARB_BP_CAP_STATUS_BS_SHIFT 2 |
---|
| 39 | +#define ARB_BP_CAP_STATUS_WRITE (1 << 1) |
---|
| 40 | +#define ARB_BP_CAP_STATUS_VALID (1 << 0) |
---|
| 41 | + |
---|
41 | 42 | enum { |
---|
42 | 43 | ARB_TIMER, |
---|
| 44 | + ARB_BP_CAP_CLR, |
---|
| 45 | + ARB_BP_CAP_HI_ADDR, |
---|
| 46 | + ARB_BP_CAP_ADDR, |
---|
| 47 | + ARB_BP_CAP_STATUS, |
---|
| 48 | + ARB_BP_CAP_MASTER, |
---|
43 | 49 | ARB_ERR_CAP_CLR, |
---|
44 | 50 | ARB_ERR_CAP_HI_ADDR, |
---|
45 | 51 | ARB_ERR_CAP_ADDR, |
---|
.. | .. |
---|
49 | 55 | |
---|
50 | 56 | static const int gisb_offsets_bcm7038[] = { |
---|
51 | 57 | [ARB_TIMER] = 0x00c, |
---|
| 58 | + [ARB_BP_CAP_CLR] = 0x014, |
---|
| 59 | + [ARB_BP_CAP_HI_ADDR] = -1, |
---|
| 60 | + [ARB_BP_CAP_ADDR] = 0x0b8, |
---|
| 61 | + [ARB_BP_CAP_STATUS] = 0x0c0, |
---|
| 62 | + [ARB_BP_CAP_MASTER] = -1, |
---|
52 | 63 | [ARB_ERR_CAP_CLR] = 0x0c4, |
---|
53 | 64 | [ARB_ERR_CAP_HI_ADDR] = -1, |
---|
54 | 65 | [ARB_ERR_CAP_ADDR] = 0x0c8, |
---|
.. | .. |
---|
58 | 69 | |
---|
59 | 70 | static const int gisb_offsets_bcm7278[] = { |
---|
60 | 71 | [ARB_TIMER] = 0x008, |
---|
| 72 | + [ARB_BP_CAP_CLR] = 0x01c, |
---|
| 73 | + [ARB_BP_CAP_HI_ADDR] = -1, |
---|
| 74 | + [ARB_BP_CAP_ADDR] = 0x220, |
---|
| 75 | + [ARB_BP_CAP_STATUS] = 0x230, |
---|
| 76 | + [ARB_BP_CAP_MASTER] = 0x234, |
---|
61 | 77 | [ARB_ERR_CAP_CLR] = 0x7f8, |
---|
62 | 78 | [ARB_ERR_CAP_HI_ADDR] = -1, |
---|
63 | 79 | [ARB_ERR_CAP_ADDR] = 0x7e0, |
---|
.. | .. |
---|
67 | 83 | |
---|
68 | 84 | static const int gisb_offsets_bcm7400[] = { |
---|
69 | 85 | [ARB_TIMER] = 0x00c, |
---|
| 86 | + [ARB_BP_CAP_CLR] = 0x014, |
---|
| 87 | + [ARB_BP_CAP_HI_ADDR] = -1, |
---|
| 88 | + [ARB_BP_CAP_ADDR] = 0x0b8, |
---|
| 89 | + [ARB_BP_CAP_STATUS] = 0x0c0, |
---|
| 90 | + [ARB_BP_CAP_MASTER] = 0x0c4, |
---|
70 | 91 | [ARB_ERR_CAP_CLR] = 0x0c8, |
---|
71 | 92 | [ARB_ERR_CAP_HI_ADDR] = -1, |
---|
72 | 93 | [ARB_ERR_CAP_ADDR] = 0x0cc, |
---|
.. | .. |
---|
76 | 97 | |
---|
77 | 98 | static const int gisb_offsets_bcm7435[] = { |
---|
78 | 99 | [ARB_TIMER] = 0x00c, |
---|
| 100 | + [ARB_BP_CAP_CLR] = 0x014, |
---|
| 101 | + [ARB_BP_CAP_HI_ADDR] = -1, |
---|
| 102 | + [ARB_BP_CAP_ADDR] = 0x158, |
---|
| 103 | + [ARB_BP_CAP_STATUS] = 0x160, |
---|
| 104 | + [ARB_BP_CAP_MASTER] = 0x164, |
---|
79 | 105 | [ARB_ERR_CAP_CLR] = 0x168, |
---|
80 | 106 | [ARB_ERR_CAP_HI_ADDR] = -1, |
---|
81 | 107 | [ARB_ERR_CAP_ADDR] = 0x16c, |
---|
.. | .. |
---|
85 | 111 | |
---|
86 | 112 | static const int gisb_offsets_bcm7445[] = { |
---|
87 | 113 | [ARB_TIMER] = 0x008, |
---|
| 114 | + [ARB_BP_CAP_CLR] = 0x010, |
---|
| 115 | + [ARB_BP_CAP_HI_ADDR] = -1, |
---|
| 116 | + [ARB_BP_CAP_ADDR] = 0x1d8, |
---|
| 117 | + [ARB_BP_CAP_STATUS] = 0x1e0, |
---|
| 118 | + [ARB_BP_CAP_MASTER] = 0x1e4, |
---|
88 | 119 | [ARB_ERR_CAP_CLR] = 0x7e4, |
---|
89 | 120 | [ARB_ERR_CAP_HI_ADDR] = 0x7e8, |
---|
90 | 121 | [ARB_ERR_CAP_ADDR] = 0x7ec, |
---|
.. | .. |
---|
133 | 164 | return value; |
---|
134 | 165 | } |
---|
135 | 166 | |
---|
| 167 | +static u64 gisb_read_bp_address(struct brcmstb_gisb_arb_device *gdev) |
---|
| 168 | +{ |
---|
| 169 | + u64 value; |
---|
| 170 | + |
---|
| 171 | + value = gisb_read(gdev, ARB_BP_CAP_ADDR); |
---|
| 172 | + value |= (u64)gisb_read(gdev, ARB_BP_CAP_HI_ADDR) << 32; |
---|
| 173 | + |
---|
| 174 | + return value; |
---|
| 175 | +} |
---|
| 176 | + |
---|
136 | 177 | static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg) |
---|
137 | 178 | { |
---|
138 | 179 | int offset = gdev->gisb_offsets[reg]; |
---|
.. | .. |
---|
150 | 191 | struct device_attribute *attr, |
---|
151 | 192 | char *buf) |
---|
152 | 193 | { |
---|
153 | | - struct platform_device *pdev = to_platform_device(dev); |
---|
154 | | - struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); |
---|
| 194 | + struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); |
---|
155 | 195 | u32 timeout; |
---|
156 | 196 | |
---|
157 | 197 | mutex_lock(&gdev->lock); |
---|
.. | .. |
---|
165 | 205 | struct device_attribute *attr, |
---|
166 | 206 | const char *buf, size_t count) |
---|
167 | 207 | { |
---|
168 | | - struct platform_device *pdev = to_platform_device(dev); |
---|
169 | | - struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); |
---|
| 208 | + struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); |
---|
170 | 209 | int val, ret; |
---|
171 | 210 | |
---|
172 | 211 | ret = kstrtoint(buf, 10, &val); |
---|
.. | .. |
---|
220 | 259 | m_name = m_fmt; |
---|
221 | 260 | } |
---|
222 | 261 | |
---|
223 | | - pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n", |
---|
224 | | - __func__, reason, arb_addr, |
---|
| 262 | + pr_crit("GISB: %s at 0x%llx [%c %s], core: %s\n", |
---|
| 263 | + reason, arb_addr, |
---|
225 | 264 | cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R', |
---|
226 | 265 | cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "", |
---|
227 | 266 | m_name); |
---|
.. | .. |
---|
265 | 304 | static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id) |
---|
266 | 305 | { |
---|
267 | 306 | brcmstb_gisb_arb_decode_addr(dev_id, "target abort"); |
---|
| 307 | + |
---|
| 308 | + return IRQ_HANDLED; |
---|
| 309 | +} |
---|
| 310 | + |
---|
| 311 | +static irqreturn_t brcmstb_gisb_bp_handler(int irq, void *dev_id) |
---|
| 312 | +{ |
---|
| 313 | + struct brcmstb_gisb_arb_device *gdev = dev_id; |
---|
| 314 | + const char *m_name; |
---|
| 315 | + u32 bp_status; |
---|
| 316 | + u64 arb_addr; |
---|
| 317 | + u32 master; |
---|
| 318 | + char m_fmt[11]; |
---|
| 319 | + |
---|
| 320 | + bp_status = gisb_read(gdev, ARB_BP_CAP_STATUS); |
---|
| 321 | + |
---|
| 322 | + /* Invalid captured address, bail out */ |
---|
| 323 | + if (!(bp_status & ARB_BP_CAP_STATUS_VALID)) |
---|
| 324 | + return IRQ_HANDLED; |
---|
| 325 | + |
---|
| 326 | + /* Read the address and master */ |
---|
| 327 | + arb_addr = gisb_read_bp_address(gdev); |
---|
| 328 | + master = gisb_read(gdev, ARB_BP_CAP_MASTER); |
---|
| 329 | + |
---|
| 330 | + m_name = brcmstb_gisb_master_to_str(gdev, master); |
---|
| 331 | + if (!m_name) { |
---|
| 332 | + snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master); |
---|
| 333 | + m_name = m_fmt; |
---|
| 334 | + } |
---|
| 335 | + |
---|
| 336 | + pr_crit("GISB: breakpoint at 0x%llx [%c], core: %s\n", |
---|
| 337 | + arb_addr, bp_status & ARB_BP_CAP_STATUS_WRITE ? 'W' : 'R', |
---|
| 338 | + m_name); |
---|
| 339 | + |
---|
| 340 | + /* clear the GISB error */ |
---|
| 341 | + gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR); |
---|
268 | 342 | |
---|
269 | 343 | return IRQ_HANDLED; |
---|
270 | 344 | } |
---|
.. | .. |
---|
327 | 401 | struct brcmstb_gisb_arb_device *gdev; |
---|
328 | 402 | const struct of_device_id *of_id; |
---|
329 | 403 | struct resource *r; |
---|
330 | | - int err, timeout_irq, tea_irq; |
---|
| 404 | + int err, timeout_irq, tea_irq, bp_irq; |
---|
331 | 405 | unsigned int num_masters, j = 0; |
---|
332 | 406 | int i, first, last; |
---|
333 | 407 | |
---|
334 | 408 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
335 | 409 | timeout_irq = platform_get_irq(pdev, 0); |
---|
336 | 410 | tea_irq = platform_get_irq(pdev, 1); |
---|
| 411 | + bp_irq = platform_get_irq(pdev, 2); |
---|
337 | 412 | |
---|
338 | 413 | gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL); |
---|
339 | 414 | if (!gdev) |
---|
.. | .. |
---|
365 | 440 | gdev); |
---|
366 | 441 | if (err < 0) |
---|
367 | 442 | return err; |
---|
| 443 | + |
---|
| 444 | + /* Interrupt is optional */ |
---|
| 445 | + if (bp_irq > 0) { |
---|
| 446 | + err = devm_request_irq(&pdev->dev, bp_irq, |
---|
| 447 | + brcmstb_gisb_bp_handler, 0, pdev->name, |
---|
| 448 | + gdev); |
---|
| 449 | + if (err < 0) |
---|
| 450 | + return err; |
---|
| 451 | + } |
---|
368 | 452 | |
---|
369 | 453 | /* If we do not have a valid mask, assume all masters are enabled */ |
---|
370 | 454 | if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask", |
---|
.. | .. |
---|
409 | 493 | &gisb_panic_notifier); |
---|
410 | 494 | } |
---|
411 | 495 | |
---|
412 | | - dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n", |
---|
413 | | - gdev->base, timeout_irq, tea_irq); |
---|
| 496 | + dev_info(&pdev->dev, "registered irqs: %d, %d\n", |
---|
| 497 | + timeout_irq, tea_irq); |
---|
414 | 498 | |
---|
415 | 499 | return 0; |
---|
416 | 500 | } |
---|
.. | .. |
---|
418 | 502 | #ifdef CONFIG_PM_SLEEP |
---|
419 | 503 | static int brcmstb_gisb_arb_suspend(struct device *dev) |
---|
420 | 504 | { |
---|
421 | | - struct platform_device *pdev = to_platform_device(dev); |
---|
422 | | - struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); |
---|
| 505 | + struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); |
---|
423 | 506 | |
---|
424 | 507 | gdev->saved_timeout = gisb_read(gdev, ARB_TIMER); |
---|
425 | 508 | |
---|
.. | .. |
---|
431 | 514 | */ |
---|
432 | 515 | static int brcmstb_gisb_arb_resume_noirq(struct device *dev) |
---|
433 | 516 | { |
---|
434 | | - struct platform_device *pdev = to_platform_device(dev); |
---|
435 | | - struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); |
---|
| 517 | + struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); |
---|
436 | 518 | |
---|
437 | 519 | gisb_write(gdev, gdev->saved_timeout, ARB_TIMER); |
---|
438 | 520 | |
---|