|
18 | 18 | #include <linux/inetdevice.h>
|
19 | 19 | #include <linux/mbus.h>
|
20 | 20 | #include <linux/module.h>
|
| 21 | +#include <linux/mfd/syscon.h> |
21 | 22 | #include <linux/interrupt.h>
|
22 | 23 | #include <linux/cpumask.h>
|
23 | 24 | #include <linux/of.h>
|
|
30 | 31 | #include <linux/clk.h>
|
31 | 32 | #include <linux/hrtimer.h>
|
32 | 33 | #include <linux/ktime.h>
|
| 34 | +#include <linux/regmap.h> |
33 | 35 | #include <uapi/linux/ppp_defs.h>
|
34 | 36 | #include <net/ip.h>
|
35 | 37 | #include <net/ipv6.h>
|
|
388 | 390 | #define MVPP2_QUEUE_NEXT_DESC(q, index) \
|
389 | 391 | (((index) < (q)->last_desc) ? ((index) + 1) : 0)
|
390 | 392 |
|
| 393 | +/* XPCS registers. PPv2.2 only */ |
| 394 | +#define MVPP22_MPCS_BASE(port) (0x7000 + (port) * 0x1000) |
| 395 | +#define MVPP22_MPCS_CTRL 0x14 |
| 396 | +#define MVPP22_MPCS_CTRL_FWD_ERR_CONN BIT(10) |
| 397 | +#define MVPP22_MPCS_CLK_RESET 0x14c |
| 398 | +#define MAC_CLK_RESET_SD_TX BIT(0) |
| 399 | +#define MAC_CLK_RESET_SD_RX BIT(1) |
| 400 | +#define MAC_CLK_RESET_MAC BIT(2) |
| 401 | +#define MVPP22_MPCS_CLK_RESET_DIV_RATIO(n) ((n) << 4) |
| 402 | +#define MVPP22_MPCS_CLK_RESET_DIV_SET BIT(11) |
| 403 | + |
| 404 | +/* XPCS registers. PPv2.2 only */ |
| 405 | +#define MVPP22_XPCS_BASE(port) (0x7400 + (port) * 0x1000) |
| 406 | +#define MVPP22_XPCS_CFG0 0x0 |
| 407 | +#define MVPP22_XPCS_CFG0_PCS_MODE(n) ((n) << 3) |
| 408 | +#define MVPP22_XPCS_CFG0_ACTIVE_LANE(n) ((n) << 5) |
| 409 | + |
| 410 | +/* System controller registers. Accessed through a regmap. */ |
| 411 | +#define GENCONF_SOFT_RESET1 0x1108 |
| 412 | +#define GENCONF_SOFT_RESET1_GOP BIT(6) |
| 413 | +#define GENCONF_PORT_CTRL0 0x1110 |
| 414 | +#define GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT BIT(1) |
| 415 | +#define GENCONF_PORT_CTRL0_RX_DATA_SAMPLE BIT(29) |
| 416 | +#define GENCONF_PORT_CTRL0_CLK_DIV_PHASE_CLR BIT(31) |
| 417 | +#define GENCONF_PORT_CTRL1 0x1114 |
| 418 | +#define GENCONF_PORT_CTRL1_EN(p) BIT(p) |
| 419 | +#define GENCONF_PORT_CTRL1_RESET(p) (BIT(p) << 28) |
| 420 | +#define GENCONF_CTRL0 0x1120 |
| 421 | +#define GENCONF_CTRL0_PORT0_RGMII BIT(0) |
| 422 | +#define GENCONF_CTRL0_PORT1_RGMII_MII BIT(1) |
| 423 | +#define GENCONF_CTRL0_PORT1_RGMII BIT(2) |
| 424 | + |
391 | 425 | /* Various constants */
|
392 | 426 |
|
393 | 427 | /* Coalescing */
|
@@ -731,6 +765,11 @@ struct mvpp2 {
|
731 | 765 | */
|
732 | 766 | void __iomem *swth_base[MVPP2_MAX_THREADS];
|
733 | 767 |
|
| 768 | + /* On PPv2.2, some port control registers are located into the system |
| 769 | + * controller space. These registers are accessible through a regmap. |
| 770 | + */ |
| 771 | + struct regmap *sysctrl_base; |
| 772 | + |
734 | 773 | /* Common clocks */
|
735 | 774 | struct clk *pp_clk;
|
736 | 775 | struct clk *gop_clk;
|
@@ -4259,6 +4298,123 @@ mvpp2_shared_interrupt_mask_unmask(struct mvpp2_port *port, bool mask)
|
4259 | 4298 |
|
4260 | 4299 | /* Port configuration routines */
|
4261 | 4300 |
|
| 4301 | +static void mvpp22_gop_init_rgmii(struct mvpp2_port *port) |
| 4302 | +{ |
| 4303 | + struct mvpp2 *priv = port->priv; |
| 4304 | + u32 val; |
| 4305 | + |
| 4306 | + regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL0, &val); |
| 4307 | + val |= GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT; |
| 4308 | + regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val); |
| 4309 | + |
| 4310 | + regmap_read(priv->sysctrl_base, GENCONF_CTRL0, &val); |
| 4311 | + if (port->gop_id == 2) |
| 4312 | + val |= GENCONF_CTRL0_PORT0_RGMII | GENCONF_CTRL0_PORT1_RGMII; |
| 4313 | + else if (port->gop_id == 3) |
| 4314 | + val |= GENCONF_CTRL0_PORT1_RGMII_MII; |
| 4315 | + regmap_write(priv->sysctrl_base, GENCONF_CTRL0, val); |
| 4316 | +} |
| 4317 | + |
| 4318 | +static void mvpp22_gop_init_sgmii(struct mvpp2_port *port) |
| 4319 | +{ |
| 4320 | + struct mvpp2 *priv = port->priv; |
| 4321 | + u32 val; |
| 4322 | + |
| 4323 | + regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL0, &val); |
| 4324 | + val |= GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT | |
| 4325 | + GENCONF_PORT_CTRL0_RX_DATA_SAMPLE; |
| 4326 | + regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val); |
| 4327 | + |
| 4328 | + if (port->gop_id > 1) { |
| 4329 | + regmap_read(priv->sysctrl_base, GENCONF_CTRL0, &val); |
| 4330 | + if (port->gop_id == 2) |
| 4331 | + val &= ~GENCONF_CTRL0_PORT0_RGMII; |
| 4332 | + else if (port->gop_id == 3) |
| 4333 | + val &= ~GENCONF_CTRL0_PORT1_RGMII_MII; |
| 4334 | + regmap_write(priv->sysctrl_base, GENCONF_CTRL0, val); |
| 4335 | + } |
| 4336 | +} |
| 4337 | + |
| 4338 | +static void mvpp22_gop_init_10gkr(struct mvpp2_port *port) |
| 4339 | +{ |
| 4340 | + struct mvpp2 *priv = port->priv; |
| 4341 | + void __iomem *mpcs = priv->iface_base + MVPP22_MPCS_BASE(port->gop_id); |
| 4342 | + void __iomem *xpcs = priv->iface_base + MVPP22_XPCS_BASE(port->gop_id); |
| 4343 | + u32 val; |
| 4344 | + |
| 4345 | + /* XPCS */ |
| 4346 | + val = readl(xpcs + MVPP22_XPCS_CFG0); |
| 4347 | + val &= ~(MVPP22_XPCS_CFG0_PCS_MODE(0x3) | |
| 4348 | + MVPP22_XPCS_CFG0_ACTIVE_LANE(0x3)); |
| 4349 | + val |= MVPP22_XPCS_CFG0_ACTIVE_LANE(2); |
| 4350 | + writel(val, xpcs + MVPP22_XPCS_CFG0); |
| 4351 | + |
| 4352 | + /* MPCS */ |
| 4353 | + val = readl(mpcs + MVPP22_MPCS_CTRL); |
| 4354 | + val &= ~MVPP22_MPCS_CTRL_FWD_ERR_CONN; |
| 4355 | + writel(val, mpcs + MVPP22_MPCS_CTRL); |
| 4356 | + |
| 4357 | + val = readl(mpcs + MVPP22_MPCS_CLK_RESET); |
| 4358 | + val &= ~(MVPP22_MPCS_CLK_RESET_DIV_RATIO(0x7) | MAC_CLK_RESET_MAC | |
| 4359 | + MAC_CLK_RESET_SD_RX | MAC_CLK_RESET_SD_TX); |
| 4360 | + val |= MVPP22_MPCS_CLK_RESET_DIV_RATIO(1); |
| 4361 | + writel(val, mpcs + MVPP22_MPCS_CLK_RESET); |
| 4362 | + |
| 4363 | + val &= ~MVPP22_MPCS_CLK_RESET_DIV_SET; |
| 4364 | + val |= MAC_CLK_RESET_MAC | MAC_CLK_RESET_SD_RX | MAC_CLK_RESET_SD_TX; |
| 4365 | + writel(val, mpcs + MVPP22_MPCS_CLK_RESET); |
| 4366 | +} |
| 4367 | + |
| 4368 | +static int mvpp22_gop_init(struct mvpp2_port *port) |
| 4369 | +{ |
| 4370 | + struct mvpp2 *priv = port->priv; |
| 4371 | + u32 val; |
| 4372 | + |
| 4373 | + if (!priv->sysctrl_base) |
| 4374 | + return 0; |
| 4375 | + |
| 4376 | + switch (port->phy_interface) { |
| 4377 | + case PHY_INTERFACE_MODE_RGMII: |
| 4378 | + case PHY_INTERFACE_MODE_RGMII_ID: |
| 4379 | + case PHY_INTERFACE_MODE_RGMII_RXID: |
| 4380 | + case PHY_INTERFACE_MODE_RGMII_TXID: |
| 4381 | + if (port->gop_id == 0) |
| 4382 | + goto invalid_conf; |
| 4383 | + mvpp22_gop_init_rgmii(port); |
| 4384 | + break; |
| 4385 | + case PHY_INTERFACE_MODE_SGMII: |
| 4386 | + mvpp22_gop_init_sgmii(port); |
| 4387 | + break; |
| 4388 | + case PHY_INTERFACE_MODE_10GKR: |
| 4389 | + if (port->gop_id != 0) |
| 4390 | + goto invalid_conf; |
| 4391 | + mvpp22_gop_init_10gkr(port); |
| 4392 | + break; |
| 4393 | + default: |
| 4394 | + goto unsupported_conf; |
| 4395 | + } |
| 4396 | + |
| 4397 | + regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL1, &val); |
| 4398 | + val |= GENCONF_PORT_CTRL1_RESET(port->gop_id) | |
| 4399 | + GENCONF_PORT_CTRL1_EN(port->gop_id); |
| 4400 | + regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL1, val); |
| 4401 | + |
| 4402 | + regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL0, &val); |
| 4403 | + val |= GENCONF_PORT_CTRL0_CLK_DIV_PHASE_CLR; |
| 4404 | + regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val); |
| 4405 | + |
| 4406 | + regmap_read(priv->sysctrl_base, GENCONF_SOFT_RESET1, &val); |
| 4407 | + val |= GENCONF_SOFT_RESET1_GOP; |
| 4408 | + regmap_write(priv->sysctrl_base, GENCONF_SOFT_RESET1, val); |
| 4409 | + |
| 4410 | +unsupported_conf: |
| 4411 | + return 0; |
| 4412 | + |
| 4413 | +invalid_conf: |
| 4414 | + netdev_err(port->dev, "Invalid port configuration\n"); |
| 4415 | + return -EINVAL; |
| 4416 | +} |
| 4417 | + |
4262 | 4418 | static void mvpp2_port_mii_gmac_configure_mode(struct mvpp2_port *port)
|
4263 | 4419 | {
|
4264 | 4420 | u32 val;
|
@@ -6105,6 +6261,9 @@ static void mvpp2_start_dev(struct mvpp2_port *port)
|
6105 | 6261 | /* Enable interrupts on all CPUs */
|
6106 | 6262 | mvpp2_interrupts_enable(port);
|
6107 | 6263 |
|
| 6264 | + if (port->priv->hw_version == MVPP22) |
| 6265 | + mvpp22_gop_init(port); |
| 6266 | + |
6108 | 6267 | mvpp2_port_mii_set(port);
|
6109 | 6268 | mvpp2_port_enable(port);
|
6110 | 6269 | phy_start(ndev->phydev);
|
@@ -7350,6 +7509,17 @@ static int mvpp2_probe(struct platform_device *pdev)
|
7350 | 7509 | priv->iface_base = devm_ioremap_resource(&pdev->dev, res);
|
7351 | 7510 | if (IS_ERR(priv->iface_base))
|
7352 | 7511 | return PTR_ERR(priv->iface_base);
|
| 7512 | + |
| 7513 | + priv->sysctrl_base = |
| 7514 | + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, |
| 7515 | + "marvell,system-controller"); |
| 7516 | + if (IS_ERR(priv->sysctrl_base)) |
| 7517 | + /* The system controller regmap is optional for dt |
| 7518 | + * compatibility reasons. When not provided, the |
| 7519 | + * configuration of the GoP relies on the |
| 7520 | + * firmware/bootloader. |
| 7521 | + */ |
| 7522 | + priv->sysctrl_base = NULL; |
7353 | 7523 | }
|
7354 | 7524 |
|
7355 | 7525 | for (i = 0; i < MVPP2_MAX_THREADS; i++) {
|
|
0 commit comments