| .. | .. |
|---|
| 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 | |
|---|