Skip to content
Snippets Groups Projects
Commit 61ce73a5 authored by Harvey Leicester's avatar Harvey Leicester Committed by Adam Wujek
Browse files

[FEATURE: #344] kernel/wr-nic: add access to extended LPDC interface

parent b5ee6e91
Branches
Tags
No related merge requests found
##############################################################################;
## Title : PHY LPDC register layout
## Project : White Rabbit
##############################################################################;
## File : lpdc_mdio_registers.cheby
## Author : Tomasz Włostowski
##############################################################################
## Description: Xilinx-specific LPDC registers. Shared between all PHYs.
##############################################################################
##
## Copyright (c) 2023 CERN / BE-CO-HT
##
## This source file is free software; you can redistribute it
## and/or modify it under the terms of the GNU Lesser General
## Public License as published by the Free Software Foundation;
## either version 2.1 of the License, or (at your option) any
## later version.
##
## This source is distributed in the hope that it will be
## useful, but WITHOUT ANY WARRANTY; without even the implied
## warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE. See the GNU Lesser General Public License for more
## details.
##
## You should have received a copy of the GNU Lesser General
## Public License along with this source; if not, download it
## from http://www.gnu.org/licenses/lgpl-2.1l.html
##
##############################################################################-
memory-map:
name: lpdc_mdio
description: LPDC-specific MDIO registers.
bus: wb-32-be
x-hdl:
busgroup: True
iogroup: lpdc_regs
name-suffix: _regs
schema-version:
core: 2.0.0
x-conversions: 1.0.0
x-hdl: 1.0.0
x-map-info: 1.0.0
x-wbgen: 1.0.0
children:
- reg:
name: CTRL
description: Low Phase Drift Calibration Control Register
width: 32
access: rw
address: 0x0
children:
- field:
name: tx_sw_reset
description: Reset of PHY TX path
range: 0
- field:
name: tx_enable
description: Enable of the PHY TX path
range: 1
- field:
name: rx_enable
description: Enable of the PHY RX path
range: 2
- field:
name: rx_sw_reset
description: Reset of PHY RX path
range: 3
- field:
name: pll_sw_reset
description: Reset of PHY CPLL or QPLL
range: 4
- field:
name: aux_reset
description: Auxiliary Reset of PHY (for example to reset TXUSRCLK PLL)
range: 5
- field:
name: comma_target_pos
description: Desired bitslide used for comma detection
range: 13-6
- field:
name: dmtd_clk_sel
description: PHY DDMTD clock input select
comment: 00 - RXRECCLK; 01 - TXOUTCLK; other - tied to 0
range: 15-14
- reg:
name: STAT
description: Low Phase Drift Calibration Status Register
width: 32
access: ro
address: 0x4
children:
- field:
name: pll_locked
description: CPLL or QPLL lock indication
range: 0
- field:
name: link_up
description: Early link up detect
range: 1
- field:
name: link_aligned
description: Link comma alignment complete
range: 2
- field:
name: tx_rst_done
description: PHY TX path reset sequence done
range: 3
- field:
name: txusrpll_locked
description: PHY TXUSRCLK PLL lock indication
range: 4
- field:
name: rx_rst_done
description: PHY RX path reset sequence done
range: 5
- field:
name: comma_current_pos
description: Current RX comma position
range: 14-7
- field:
name: comma_pos_valid
description: 1 if comma_current_pos contains a valid comma offset
range: 15
- reg:
name: CTRL2
description: Low Phase Drift Calibration Control Register 2
width: 32
access: rw
address: 0x8
children:
- field:
name: rx_rate
description: RX clock divider
range: 2-0
- field:
name: rx_latch_pattern
description: RX idle pattern latch
range: 3
x-hdl:
type: autoclear
- field:
name: rx_gearbox_pll_reset
description: RX gearbox PLL reset
range: 4
- field:
name: rx_gearbox_pll_locked
description: RX gearbox PLL locked
range: 5
x-hdl:
type: wire
- field:
name: rx_cdr_locked
description: RX CDR (PMA clock domain) locked
range: 6
x-hdl:
type: wire
- repeat:
name: idle_pat
count: 12
children:
- reg:
name: data
access: ro
width: 32
- submap:
name: drp_regs
size: 0x1000
description: Xilinx DRP registers, specific to the transceiver
interface: wb-32-be
x-hdl:
busgroup: True
\ No newline at end of file
#ifndef __CHEBY__LPDC_MDIO__H__
#define __CHEBY__LPDC_MDIO__H__
#define LPDC_MDIO_SIZE 8192 /* 0x2000 = 8KB */
/* Low Phase Drift Calibration Control Register */
#define LPDC_MDIO_CTRL 0x0UL
#define LPDC_MDIO_CTRL_TX_SW_RESET 0x1UL
#define LPDC_MDIO_CTRL_TX_ENABLE 0x2UL
#define LPDC_MDIO_CTRL_RX_ENABLE 0x4UL
#define LPDC_MDIO_CTRL_RX_SW_RESET 0x8UL
#define LPDC_MDIO_CTRL_PLL_SW_RESET 0x10UL
#define LPDC_MDIO_CTRL_AUX_RESET 0x20UL
#define LPDC_MDIO_CTRL_COMMA_TARGET_POS_MASK 0x3fc0UL
#define LPDC_MDIO_CTRL_COMMA_TARGET_POS_SHIFT 6
#define LPDC_MDIO_CTRL_DMTD_CLK_SEL_MASK 0xc000UL
#define LPDC_MDIO_CTRL_DMTD_CLK_SEL_SHIFT 14
/* Low Phase Drift Calibration Status Register */
#define LPDC_MDIO_STAT 0x4UL
#define LPDC_MDIO_STAT_PLL_LOCKED 0x1UL
#define LPDC_MDIO_STAT_LINK_UP 0x2UL
#define LPDC_MDIO_STAT_LINK_ALIGNED 0x4UL
#define LPDC_MDIO_STAT_TX_RST_DONE 0x8UL
#define LPDC_MDIO_STAT_TXUSRPLL_LOCKED 0x10UL
#define LPDC_MDIO_STAT_RX_RST_DONE 0x20UL
#define LPDC_MDIO_STAT_COMMA_CURRENT_POS_MASK 0x7f80UL
#define LPDC_MDIO_STAT_COMMA_CURRENT_POS_SHIFT 7
#define LPDC_MDIO_STAT_COMMA_POS_VALID 0x8000UL
/* Low Phase Drift Calibration Control Register 2 */
#define LPDC_MDIO_CTRL2 0x8UL
#define LPDC_MDIO_CTRL2_RX_RATE_MASK 0x7UL
#define LPDC_MDIO_CTRL2_RX_RATE_SHIFT 0
#define LPDC_MDIO_CTRL2_RX_LATCH_PATTERN 0x8UL
#define LPDC_MDIO_CTRL2_RX_GEARBOX_PLL_RESET 0x10UL
#define LPDC_MDIO_CTRL2_RX_GEARBOX_PLL_LOCKED 0x20UL
#define LPDC_MDIO_CTRL2_RX_CDR_LOCKED 0x40UL
/* None */
#define LPDC_MDIO_IDLE_PAT 0x40UL
#define LPDC_MDIO_IDLE_PAT_SIZE 4 /* 0x4 */
/* None */
#define LPDC_MDIO_IDLE_PAT_DATA 0x0UL
/* Xilinx DRP registers, specific to the transceiver */
#define LPDC_MDIO_DRP_REGS 0x1000UL
#define ADDR_MASK_LPDC_MDIO_DRP_REGS 0x1000UL
#define LPDC_MDIO_DRP_REGS_SIZE 4096 /* 0x1000 = 4KB */
#ifndef __ASSEMBLER__
struct lpdc_mdio {
/* [0x0]: REG (rw) Low Phase Drift Calibration Control Register */
uint32_t CTRL;
/* [0x4]: REG (ro) Low Phase Drift Calibration Status Register */
uint32_t STAT;
/* [0x8]: REG (rw) Low Phase Drift Calibration Control Register 2 */
uint32_t CTRL2;
/* padding to: 64 Bytes */
uint32_t __padding_0[13];
/* [0x40]: REPEAT (no description) */
struct idle_pat {
/* [0x0]: REG (ro) (no description) */
uint32_t data;
} idle_pat[12];
/* padding to: 64 Bytes */
uint32_t __padding_1[4];
/* padding to: 4096 Bytes */
uint32_t __padding_2[992];
/* [0x1000]: SUBMAP Xilinx DRP registers, specific to the transceiver */
uint32_t drp_regs[1024];
};
#endif /* !__ASSEMBLER__*/
#endif /* __CHEBY__LPDC_MDIO__H__ */
......@@ -46,6 +46,71 @@ __weak int mac_pton(const char *s, u8 *mac)
return 1;
}
/*
* LPDC access
* use extended proxy interface from wrpc-v5.0
*/
int wrn_lpdc_read(struct net_device *dev, int phy_id, int location)
{
struct wrn_ep *ep = netdev_priv(dev);
u32 val;
if (WR_IS_NODE) {
/*
* We cannot access the phy from Linux, because the phy
* is managed by the lm32 core. However, network manager
* insists on doing that, so we'd better not warn about it
*/
//WARN_ON(1); /* SPEC: no access */
return -1;
}
/* First check if there is previous MDIO operation still ongoing */
while ( (wrn_ep_read(ep, MDIO_ASR) & EP_MDIO_ASR_READY) == 0)
;
/* Select lpdc submap */
wrn_ep_write(ep, MDIO_ASR, 0x00080000);
while ( (wrn_ep_read(ep, MDIO_ASR) & EP_MDIO_ASR_READY) == 0)
;
val = wrn_phy_read(dev, phy_id, location >> 2);
/* Deselect lpdc submap */
wrn_ep_write(ep, MDIO_ASR, 0x00000000);
return val;
}
void wrn_lpdc_write(struct net_device *dev, int phy_id, int location,
int value)
{
struct wrn_ep *ep = netdev_priv(dev);
if (WR_IS_NODE) {
/*
* We cannot access the phy from Linux, because the phy
* is managed by the lm32 core. However, network manager
* insists on doing that, so we'd better not warn about it
*/
//WARN_ON(1); /* SPEC: no access */
return;
}
/* First check if there is previous MDIO operation still ongoing */
while ( (wrn_ep_read(ep, MDIO_ASR) & EP_MDIO_ASR_READY) == 0)
;
/* Select lpdc submap */
wrn_ep_write(ep, MDIO_ASR, 0x00080000);
while ( (wrn_ep_read(ep, MDIO_ASR) & EP_MDIO_ASR_READY) == 0)
;
wrn_phy_write(dev, phy_id, location >> 2, value);
/* Deselect lpdc submap */
wrn_ep_write(ep, MDIO_ASR, 0x00000000);
}
/*
* Phy access: used by link status, enable, calibration ioctl etc.
* Called with endpoint lock (you'll lock the whole sequence of r/w)
......
......@@ -295,7 +295,7 @@ static int wrn_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/* this command allows to read and write a phy register */
if (get_user(reg, (u32 *)rq->ifr_data) < 0)
return -EFAULT;
if (reg & (1<<31)) {
if (reg & (1 << 31)) {
wrn_phy_write(dev, 0, (reg >> 16) & 0xff,
reg & 0xffff);
return 0;
......@@ -304,7 +304,19 @@ static int wrn_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (put_user(reg, (u32 *)rq->ifr_data) < 0)
return -EFAULT;
return 0;
case PRIV_IOCLPDCREG:
/* this command allows to read and write a phy lpdc register */
if (get_user(reg, (u32 *)rq->ifr_data) < 0)
return -EFAULT;
if (reg & (1 << 31)) {
wrn_lpdc_write(dev, 0, (reg >> 16) & 0xff,
reg & 0xffff);
return 0;
}
reg = wrn_lpdc_read(dev, 0, (reg >> 16) & 0xff);
if (put_user(reg, (u32 *)rq->ifr_data) < 0)
return -EFAULT;
return 0;
case PRIV_MEZZANINE_ID:
case PRIV_MEZZANINE_CMD:
/* Pass this to the mezzanine driver, or use internal weak */
......
......@@ -18,6 +18,8 @@
#define PRIV_IOCGGETPHASE (SIOCDEVPRIVATE + 2)
#define PRIV_IOCREADREG (SIOCDEVPRIVATE + 3)
#define PRIV_IOCPHYREG (SIOCDEVPRIVATE + 4)
#define PRIV_IOCLPDCREG (SIOCDEVPRIVATE + 5)
/* The last two available are used for mezzanine-private stuff */
#define PRIV_MEZZANINE_ID (SIOCDEVPRIVATE + 14)
......@@ -232,6 +234,9 @@ extern int wrn_ethtool_init(struct net_device *netdev);
/* Following functions in endpoint.c */
extern int wrn_phy_read(struct net_device *dev, int phy_id, int location);
extern void wrn_phy_write(struct net_device *dev, int phy_id, int loc, int v);
extern int wrn_lpdc_read(struct net_device *dev, int phy_id, int location);
extern void wrn_lpdc_write(struct net_device *dev, int phy_id, int loc, int v);
extern int wrn_ep_open(struct net_device *dev);
extern int wrn_ep_close(struct net_device *dev);
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment