.. | .. |
---|
19 | 19 | #include <linux/kernel.h> |
---|
20 | 20 | #include <linux/module.h> |
---|
21 | 21 | #include <linux/delay.h> |
---|
| 22 | +#include <linux/interrupt.h> |
---|
22 | 23 | #include <linux/platform_device.h> |
---|
23 | 24 | #include <linux/platform_data/b53.h> |
---|
24 | 25 | #include <linux/of.h> |
---|
25 | 26 | |
---|
26 | 27 | #include "b53_priv.h" |
---|
| 28 | +#include "b53_serdes.h" |
---|
27 | 29 | |
---|
28 | 30 | /* command and status register of the SRAB */ |
---|
29 | 31 | #define B53_SRAB_CMDSTAT 0x2c |
---|
.. | .. |
---|
47 | 49 | |
---|
48 | 50 | /* command and status register of the SRAB */ |
---|
49 | 51 | #define B53_SRAB_CTRLS 0x40 |
---|
| 52 | +#define B53_SRAB_CTRLS_HOST_INTR BIT(1) |
---|
50 | 53 | #define B53_SRAB_CTRLS_RCAREQ BIT(3) |
---|
51 | 54 | #define B53_SRAB_CTRLS_RCAGNT BIT(4) |
---|
52 | 55 | #define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6) |
---|
.. | .. |
---|
60 | 63 | #define B53_SRAB_P7_SLEEP_TIMER BIT(11) |
---|
61 | 64 | #define B53_SRAB_IMP0_SLEEP_TIMER BIT(12) |
---|
62 | 65 | |
---|
| 66 | +/* Port mux configuration registers */ |
---|
| 67 | +#define B53_MUX_CONFIG_P5 0x00 |
---|
| 68 | +#define MUX_CONFIG_SGMII 0 |
---|
| 69 | +#define MUX_CONFIG_MII_LITE 1 |
---|
| 70 | +#define MUX_CONFIG_RGMII 2 |
---|
| 71 | +#define MUX_CONFIG_GMII 3 |
---|
| 72 | +#define MUX_CONFIG_GPHY 4 |
---|
| 73 | +#define MUX_CONFIG_INTERNAL 5 |
---|
| 74 | +#define MUX_CONFIG_MASK 0x7 |
---|
| 75 | +#define B53_MUX_CONFIG_P4 0x04 |
---|
| 76 | + |
---|
| 77 | +struct b53_srab_port_priv { |
---|
| 78 | + int irq; |
---|
| 79 | + bool irq_enabled; |
---|
| 80 | + struct b53_device *dev; |
---|
| 81 | + unsigned int num; |
---|
| 82 | + phy_interface_t mode; |
---|
| 83 | +}; |
---|
| 84 | + |
---|
63 | 85 | struct b53_srab_priv { |
---|
64 | 86 | void __iomem *regs; |
---|
| 87 | + void __iomem *mux_config; |
---|
| 88 | + struct b53_srab_port_priv port_intrs[B53_N_PORTS]; |
---|
65 | 89 | }; |
---|
66 | 90 | |
---|
67 | 91 | static int b53_srab_request_grant(struct b53_device *dev) |
---|
.. | .. |
---|
344 | 368 | return ret; |
---|
345 | 369 | } |
---|
346 | 370 | |
---|
| 371 | +static irqreturn_t b53_srab_port_thread(int irq, void *dev_id) |
---|
| 372 | +{ |
---|
| 373 | + struct b53_srab_port_priv *port = dev_id; |
---|
| 374 | + struct b53_device *dev = port->dev; |
---|
| 375 | + |
---|
| 376 | + if (port->mode == PHY_INTERFACE_MODE_SGMII) |
---|
| 377 | + b53_port_event(dev->ds, port->num); |
---|
| 378 | + |
---|
| 379 | + return IRQ_HANDLED; |
---|
| 380 | +} |
---|
| 381 | + |
---|
| 382 | +static irqreturn_t b53_srab_port_isr(int irq, void *dev_id) |
---|
| 383 | +{ |
---|
| 384 | + struct b53_srab_port_priv *port = dev_id; |
---|
| 385 | + struct b53_device *dev = port->dev; |
---|
| 386 | + struct b53_srab_priv *priv = dev->priv; |
---|
| 387 | + |
---|
| 388 | + /* Acknowledge the interrupt */ |
---|
| 389 | + writel(BIT(port->num), priv->regs + B53_SRAB_INTR); |
---|
| 390 | + |
---|
| 391 | + return IRQ_WAKE_THREAD; |
---|
| 392 | +} |
---|
| 393 | + |
---|
| 394 | +#if IS_ENABLED(CONFIG_B53_SERDES) |
---|
| 395 | +static u8 b53_srab_serdes_map_lane(struct b53_device *dev, int port) |
---|
| 396 | +{ |
---|
| 397 | + struct b53_srab_priv *priv = dev->priv; |
---|
| 398 | + struct b53_srab_port_priv *p = &priv->port_intrs[port]; |
---|
| 399 | + |
---|
| 400 | + if (p->mode != PHY_INTERFACE_MODE_SGMII) |
---|
| 401 | + return B53_INVALID_LANE; |
---|
| 402 | + |
---|
| 403 | + switch (port) { |
---|
| 404 | + case 5: |
---|
| 405 | + return 0; |
---|
| 406 | + case 4: |
---|
| 407 | + return 1; |
---|
| 408 | + default: |
---|
| 409 | + return B53_INVALID_LANE; |
---|
| 410 | + } |
---|
| 411 | +} |
---|
| 412 | +#endif |
---|
| 413 | + |
---|
| 414 | +static int b53_srab_irq_enable(struct b53_device *dev, int port) |
---|
| 415 | +{ |
---|
| 416 | + struct b53_srab_priv *priv = dev->priv; |
---|
| 417 | + struct b53_srab_port_priv *p = &priv->port_intrs[port]; |
---|
| 418 | + int ret = 0; |
---|
| 419 | + |
---|
| 420 | + /* Interrupt is optional and was not specified, do not make |
---|
| 421 | + * this fatal |
---|
| 422 | + */ |
---|
| 423 | + if (p->irq == -ENXIO) |
---|
| 424 | + return ret; |
---|
| 425 | + |
---|
| 426 | + ret = request_threaded_irq(p->irq, b53_srab_port_isr, |
---|
| 427 | + b53_srab_port_thread, 0, |
---|
| 428 | + dev_name(dev->dev), p); |
---|
| 429 | + if (!ret) |
---|
| 430 | + p->irq_enabled = true; |
---|
| 431 | + |
---|
| 432 | + return ret; |
---|
| 433 | +} |
---|
| 434 | + |
---|
| 435 | +static void b53_srab_irq_disable(struct b53_device *dev, int port) |
---|
| 436 | +{ |
---|
| 437 | + struct b53_srab_priv *priv = dev->priv; |
---|
| 438 | + struct b53_srab_port_priv *p = &priv->port_intrs[port]; |
---|
| 439 | + |
---|
| 440 | + if (p->irq_enabled) { |
---|
| 441 | + free_irq(p->irq, p); |
---|
| 442 | + p->irq_enabled = false; |
---|
| 443 | + } |
---|
| 444 | +} |
---|
| 445 | + |
---|
347 | 446 | static const struct b53_io_ops b53_srab_ops = { |
---|
348 | 447 | .read8 = b53_srab_read8, |
---|
349 | 448 | .read16 = b53_srab_read16, |
---|
.. | .. |
---|
355 | 454 | .write32 = b53_srab_write32, |
---|
356 | 455 | .write48 = b53_srab_write48, |
---|
357 | 456 | .write64 = b53_srab_write64, |
---|
| 457 | + .irq_enable = b53_srab_irq_enable, |
---|
| 458 | + .irq_disable = b53_srab_irq_disable, |
---|
| 459 | +#if IS_ENABLED(CONFIG_B53_SERDES) |
---|
| 460 | + .serdes_map_lane = b53_srab_serdes_map_lane, |
---|
| 461 | + .serdes_link_state = b53_serdes_link_state, |
---|
| 462 | + .serdes_config = b53_serdes_config, |
---|
| 463 | + .serdes_an_restart = b53_serdes_an_restart, |
---|
| 464 | + .serdes_link_set = b53_serdes_link_set, |
---|
| 465 | + .serdes_phylink_validate = b53_serdes_phylink_validate, |
---|
| 466 | +#endif |
---|
358 | 467 | }; |
---|
359 | 468 | |
---|
360 | 469 | static const struct of_device_id b53_srab_of_match[] = { |
---|
.. | .. |
---|
379 | 488 | }; |
---|
380 | 489 | MODULE_DEVICE_TABLE(of, b53_srab_of_match); |
---|
381 | 490 | |
---|
| 491 | +static void b53_srab_intr_set(struct b53_srab_priv *priv, bool set) |
---|
| 492 | +{ |
---|
| 493 | + u32 reg; |
---|
| 494 | + |
---|
| 495 | + reg = readl(priv->regs + B53_SRAB_CTRLS); |
---|
| 496 | + if (set) |
---|
| 497 | + reg |= B53_SRAB_CTRLS_HOST_INTR; |
---|
| 498 | + else |
---|
| 499 | + reg &= ~B53_SRAB_CTRLS_HOST_INTR; |
---|
| 500 | + writel(reg, priv->regs + B53_SRAB_CTRLS); |
---|
| 501 | +} |
---|
| 502 | + |
---|
| 503 | +static void b53_srab_prepare_irq(struct platform_device *pdev) |
---|
| 504 | +{ |
---|
| 505 | + struct b53_device *dev = platform_get_drvdata(pdev); |
---|
| 506 | + struct b53_srab_priv *priv = dev->priv; |
---|
| 507 | + struct b53_srab_port_priv *port; |
---|
| 508 | + unsigned int i; |
---|
| 509 | + char *name; |
---|
| 510 | + |
---|
| 511 | + /* Clear all pending interrupts */ |
---|
| 512 | + writel(0xffffffff, priv->regs + B53_SRAB_INTR); |
---|
| 513 | + |
---|
| 514 | + for (i = 0; i < B53_N_PORTS; i++) { |
---|
| 515 | + port = &priv->port_intrs[i]; |
---|
| 516 | + |
---|
| 517 | + /* There is no port 6 */ |
---|
| 518 | + if (i == 6) |
---|
| 519 | + continue; |
---|
| 520 | + |
---|
| 521 | + name = kasprintf(GFP_KERNEL, "link_state_p%d", i); |
---|
| 522 | + if (!name) |
---|
| 523 | + return; |
---|
| 524 | + |
---|
| 525 | + port->num = i; |
---|
| 526 | + port->dev = dev; |
---|
| 527 | + port->irq = platform_get_irq_byname_optional(pdev, name); |
---|
| 528 | + kfree(name); |
---|
| 529 | + } |
---|
| 530 | + |
---|
| 531 | + b53_srab_intr_set(priv, true); |
---|
| 532 | +} |
---|
| 533 | + |
---|
| 534 | +static void b53_srab_mux_init(struct platform_device *pdev) |
---|
| 535 | +{ |
---|
| 536 | + struct b53_device *dev = platform_get_drvdata(pdev); |
---|
| 537 | + struct b53_srab_priv *priv = dev->priv; |
---|
| 538 | + struct b53_srab_port_priv *p; |
---|
| 539 | + unsigned int port; |
---|
| 540 | + u32 reg, off = 0; |
---|
| 541 | + int ret; |
---|
| 542 | + |
---|
| 543 | + if (dev->pdata && dev->pdata->chip_id != BCM58XX_DEVICE_ID) |
---|
| 544 | + return; |
---|
| 545 | + |
---|
| 546 | + priv->mux_config = devm_platform_ioremap_resource(pdev, 1); |
---|
| 547 | + if (IS_ERR(priv->mux_config)) |
---|
| 548 | + return; |
---|
| 549 | + |
---|
| 550 | + /* Obtain the port mux configuration so we know which lanes |
---|
| 551 | + * actually map to SerDes lanes |
---|
| 552 | + */ |
---|
| 553 | + for (port = 5; port > 3; port--, off += 4) { |
---|
| 554 | + p = &priv->port_intrs[port]; |
---|
| 555 | + |
---|
| 556 | + reg = readl(priv->mux_config + B53_MUX_CONFIG_P5 + off); |
---|
| 557 | + switch (reg & MUX_CONFIG_MASK) { |
---|
| 558 | + case MUX_CONFIG_SGMII: |
---|
| 559 | + p->mode = PHY_INTERFACE_MODE_SGMII; |
---|
| 560 | + ret = b53_serdes_init(dev, port); |
---|
| 561 | + if (ret) |
---|
| 562 | + continue; |
---|
| 563 | + break; |
---|
| 564 | + case MUX_CONFIG_MII_LITE: |
---|
| 565 | + p->mode = PHY_INTERFACE_MODE_MII; |
---|
| 566 | + break; |
---|
| 567 | + case MUX_CONFIG_GMII: |
---|
| 568 | + p->mode = PHY_INTERFACE_MODE_GMII; |
---|
| 569 | + break; |
---|
| 570 | + case MUX_CONFIG_RGMII: |
---|
| 571 | + p->mode = PHY_INTERFACE_MODE_RGMII; |
---|
| 572 | + break; |
---|
| 573 | + case MUX_CONFIG_INTERNAL: |
---|
| 574 | + p->mode = PHY_INTERFACE_MODE_INTERNAL; |
---|
| 575 | + break; |
---|
| 576 | + default: |
---|
| 577 | + p->mode = PHY_INTERFACE_MODE_NA; |
---|
| 578 | + break; |
---|
| 579 | + } |
---|
| 580 | + |
---|
| 581 | + if (p->mode != PHY_INTERFACE_MODE_NA) |
---|
| 582 | + dev_info(&pdev->dev, "Port %d mode: %s\n", |
---|
| 583 | + port, phy_modes(p->mode)); |
---|
| 584 | + } |
---|
| 585 | +} |
---|
| 586 | + |
---|
382 | 587 | static int b53_srab_probe(struct platform_device *pdev) |
---|
383 | 588 | { |
---|
384 | 589 | struct b53_platform_data *pdata = pdev->dev.platform_data; |
---|
.. | .. |
---|
386 | 591 | const struct of_device_id *of_id = NULL; |
---|
387 | 592 | struct b53_srab_priv *priv; |
---|
388 | 593 | struct b53_device *dev; |
---|
389 | | - struct resource *r; |
---|
390 | 594 | |
---|
391 | 595 | if (dn) |
---|
392 | 596 | of_id = of_match_node(b53_srab_of_match, dn); |
---|
.. | .. |
---|
403 | 607 | if (!priv) |
---|
404 | 608 | return -ENOMEM; |
---|
405 | 609 | |
---|
406 | | - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
407 | | - priv->regs = devm_ioremap_resource(&pdev->dev, r); |
---|
| 610 | + priv->regs = devm_platform_ioremap_resource(pdev, 0); |
---|
408 | 611 | if (IS_ERR(priv->regs)) |
---|
409 | | - return -ENOMEM; |
---|
| 612 | + return PTR_ERR(priv->regs); |
---|
410 | 613 | |
---|
411 | 614 | dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv); |
---|
412 | 615 | if (!dev) |
---|
.. | .. |
---|
417 | 620 | |
---|
418 | 621 | platform_set_drvdata(pdev, dev); |
---|
419 | 622 | |
---|
| 623 | + b53_srab_prepare_irq(pdev); |
---|
| 624 | + b53_srab_mux_init(pdev); |
---|
| 625 | + |
---|
420 | 626 | return b53_switch_register(dev); |
---|
421 | 627 | } |
---|
422 | 628 | |
---|
423 | 629 | static int b53_srab_remove(struct platform_device *pdev) |
---|
424 | 630 | { |
---|
425 | 631 | struct b53_device *dev = platform_get_drvdata(pdev); |
---|
| 632 | + struct b53_srab_priv *priv = dev->priv; |
---|
426 | 633 | |
---|
| 634 | + b53_srab_intr_set(priv, false); |
---|
427 | 635 | if (dev) |
---|
428 | 636 | b53_switch_remove(dev); |
---|
429 | 637 | |
---|