Compare commits

..

24 Commits

Author SHA1 Message Date
7e0984e70f Tweak config-5.4 to admit the VSC848X phy 2021-02-16 03:42:47 +00:00
ad6a039808 Boot OF_I2C || O2_SPI dependency 2021-02-16 03:38:33 +00:00
34ee966cba Further cleanup 2021-02-16 03:27:39 +00:00
8d73f4e647 Fixup patches 2021-02-16 03:06:35 +00:00
4f8715bdbf Add further patches 2021-02-16 02:05:16 +00:00
d803c68954 Fixup spacing, again 2021-02-16 01:50:30 +00:00
b5d1f3cbc3 Fixup spacing 2021-02-16 01:47:43 +00:00
15977758ba Rebase patch on newer kernel 2021-02-16 01:44:01 +00:00
319b41636f Add vsc phy 2021-02-16 01:19:54 +00:00
99afb6ba21 oops 2021-02-10 23:57:52 +00:00
47890af657 Re-enable SFP on the snic10e :^) 2021-02-10 23:44:30 +00:00
0ea1b55c49 gotcha binch 2021-02-10 23:30:36 +00:00
6e303ca958 patch in even more debugs -- all for xaui init 2021-02-10 23:18:31 +00:00
c316f05f21 debug even deeper into cvmx_ipd_enable 2021-02-10 22:47:35 +00:00
a78fd8e4b7 Fix a typo in a cvmx patch 2021-02-10 22:17:14 +00:00
665d617447 do not redundantly patch 2021-02-10 22:16:53 +00:00
fea3bae7b1 Revert "maybe never init xaui"
This reverts commit d8c455f988.

let's try ethernet again!
2021-02-10 20:39:50 +00:00
b1ce6e7731 add debugs everywhere to octeon eth setup stuff 2021-02-10 20:39:03 +00:00
dc24dcbe61 Set up the right clock frequency for serial consoles 2021-02-10 16:24:15 +00:00
796917cb6e mark opts for octeon2 and cn63xxp1 2021-02-10 15:27:27 +00:00
d8c455f988 maybe never init xaui 2021-02-10 15:27:05 +00:00
0e6edfac4a fixup 2021-02-10 15:26:18 +00:00
3c4ceb938e auuuhgh 2021-02-10 04:20:41 +00:00
b669600823 Add support for snic10e 2021-02-10 03:40:27 +00:00
11 changed files with 2385 additions and 3 deletions

View File

@ -22,6 +22,10 @@ do_sysinfo_octeon() {
return 0
;;
"SNIC10E"*)
name="snic10e"
;;
"ITUS_SHIELD"*)
name="itus,shield-router"
;;

View File

@ -24,8 +24,9 @@ CONFIG_BLK_DEV_SD=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_SCSI_REQUEST=y
CONFIG_BUILTIN_DTB=y
# CONFIG_CAVIUM_CN63XXP1 is not set
CONFIG_CAVIUM_CN63XXP1=y
CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE=0
CONFIG_CAVIUM_OCTEON2=y
CONFIG_CAVIUM_OCTEON_LOCK_L2=y
CONFIG_CAVIUM_OCTEON_LOCK_L2_EXCEPTION=y
CONFIG_CAVIUM_OCTEON_LOCK_L2_INTERRUPT=y
@ -158,6 +159,7 @@ CONFIG_HZ_250=y
CONFIG_HZ_PERIODIC=y
CONFIG_IMAGE_CMDLINE_HACK=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_OCTEON=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
@ -204,8 +206,10 @@ CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NLS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
@ -226,22 +230,25 @@ CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
CONFIG_OF_MDIO=y
CONFIG_OF_MEMORY_ACCESSOR=y
CONFIG_OF_NET=y
CONFIG_PADATA=y
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PCIEAER=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=3
CONFIG_PHYLIB=y
CONFIG_PHYLINK=y
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_RAS=y
CONFIG_RCU_NEED_SEGCBLIST=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_RELAY=y
@ -259,6 +266,7 @@ CONFIG_SPARSEMEM=y
CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SPI_OCTEON=y
CONFIG_SRCU=y
CONFIG_SWIOTLB=y
@ -294,6 +302,7 @@ CONFIG_USE_OF=y
CONFIG_VFAT_FS=y
CONFIG_VITESSE_PHY=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_VSC848X_PHY=y
CONFIG_WATCHDOG_CORE=y
CONFIG_WEAK_ORDERING=y
CONFIG_XPS=y

View File

@ -0,0 +1,847 @@
/dts-v1/;
/*
* Cavium Inc. (Small) NIC10e board
*/
/ {
model = "cavium,snic10e";
compatible = "cavium,snic10e";
#address-cells = <2>;
#size-cells = <2>;
interrupt-parent = <&ciu>;
soc@0 {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <2>;
ranges; /* Direct mapping */
ciu: interrupt-controller@1070000000000 {
compatible = "cavium,octeon-3860-ciu";
interrupt-controller;
/* Interrupts are specified by two parts:
* 1) Controller register (0 or 1)
* 2) Bit within the register (0..63)
*/
#interrupt-cells = <2>;
reg = <0x10700 0x00000000 0x0 0x7000>;
};
gpio: gpio-controller@1070000000800 {
#gpio-cells = <2>;
compatible = "cavium,octeon-3860-gpio";
reg = <0x10700 0x00000800 0x0 0x100>;
gpio-controller;
/* Interrupts are specified by two parts:
* 1) GPIO pin number (0..15)
* 2) Triggering (1 - edge rising
* 2 - edge falling
* 4 - level active high
* 8 - level active low)
*/
interrupt-controller;
#interrupt-cells = <2>;
/* The GPIO pins connect to 16 consecutive CUI bits */
interrupts = <0 16>; /* <0 17> <0 18> <0 19>
<0 20> <0 21> <0 22> <0 23>
<0 24> <0 25> <0 26> <0 27>
<0 28> <0 29> <0 30> <0 31>; */
};
twsi0: i2c@1180000001000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "cavium,octeon-3860-twsi";
reg = <0x11800 0x00001000 0x0 0x200>;
interrupts = <0 45>;
/* NOTE: In order to get the proper delay between
* i2c bus transactions for the SFP we need to either
* slow the bus down to no more than 30KHz or else
* somehow insert a delay between transactions. Only
* U-Boot is capable of inserting the appropriate delay
* at this time.
*/
clock-frequency = <30000>;
tmp@4c {
compatible = "ti,tmp421";
reg = <0x4c>;
};
sfp0: eeprom@50 {
compatible = "atmel,24c01";
reg = <0x50>;
};
tlv-eeprom@53 {
compatible = "atmel,24c256";
reg = <0x53>;
pagesize = <64>;
};
};
twsi1: i2c@1180000001200 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "cavium,octeon-3860-twsi";
reg = <0x11800 0x00001200 0x0 0x200>;
interrupts = <0 59>;
/* NOTE: In order to get the proper delay between
* i2c bus transactions for the SFP we need to either
* slow the bus down to no more than 30KHz or else
* somehow insert a delay between transactions. Only
* U-Boot is capable of inserting the appropriate delay
* at this time.
*/
clock-frequency = <30000>;
sfp1: eeprom@50 {
compatible = "atmel,24c01";
reg = <0x50>;
};
gpio1: gpio@20 {
reg = <0x20>;
compatible = "nxp,pca9554";
gpio-controller;
#gpio-cells = <2>;
interrupt-parent = <&gpio>;
interrupt = <13 2>; /* OCTEON GPIO 13, falling edge */
#interrupt-cells = <1>;
cavium,phy-trim = "0,ti";
};
};
smi0: mdio@1180000001800 {
compatible = "cavium,octeon-3860-mdio";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x11800 0x00001800 0x0 0x40>;
status = "disabled";
mphyA: ethernet-phy-nexus@A {
reg = <0>;
/* The Vitesse VSC8488 is a dual-PHY where
* some of the configuration is common across
* both of the phy devices such as the reset
* line and the base MDIO address.
*/
compatible = "vitesse,vsc8488-nexus", "ethernet-phy-nexus";
#address-cells = <1>;
#size-cells = <0>;
ranges;
cavium,phy-trim = "0,vitesse";
/* Hardware reset signal */
reset = <&gpio 17 0>;
phy0: ethernet-phy@0 {
/* Absolute address */
reg = <0>;
compatible = "vitesse,vsc8488", "ethernet-phy-ieee802.3-c45";
interrupt-parent = <&gpio>;
interrupts = <13 8>;
mod_abs = <0>;
/* TX Fault GPIO line */
tx_fault = <1>;
/* GPIO that enables output */
txon = <4>;
/* INT A GPIO output */
inta = <5>;
/* Optional equalization value to
* program into the PHY XS XAUI Rx
* Equalization control register.
* It is broken up into one nibble for
* each lane with lane 0 using bits
* 12 - 15.
* Use the following table:
* 0x0 - 0dB
* 0x1 - 1.41dB
* 0x2 - 2.24dB
* 0x3 - 2.83dB
* 0x5 - 4.48dB
* 0x6 - 5.39dB
* 0x7 - 6.07dB
* 0x9 - 6.18dB
* 0xA - 7.08dB (default)
* 0xB - 7.79dB
* 0xD - 9.96dB
* 0xE - 10.84dB
* 0xF - 11.55dB
*
* This is board specific and should
* only be defined by the hardware
* vendor.
*/
vitesse,rx_equalization = <0x0000>;
/* Optional transmit pre-emphasis
* control. This sets the
* PHY XS XAUI TX pre-emphasis control
* register.
*
* It uses bits 13-14 for lane 0,
* 10-11 for lane 1, 7-8 for lane 2
* and 4-5 for lane 3.
*
* Bits 2-3 are the LOS threshold
* setting and bit 1 enables
* the XAUI output high swing mode.
*
* Use the following table for
* pre-emphasis:
* 0b00 - 0dB
* 0b01 - 2.5dB
* 0b10 - 6dB (default)
* 0b11 - 12dB
*
* Use the following table for the LOS
* threshold setting:
*
* 0b00 - 50mV - 175mV (default)
* 0b01 - 60mV - 185mV
* 0b10 - 70mV - 195mV
* 0b11 - 80mV - 205mV
*/
vitesse,tx_preemphasis = <0x0000>;
/* TX output driver slew rate control
* is bits 8-11 where 0x0 is the minimum
* and 0xF is the maximum.
* Default is 0xA.
*
* The TX output driver C(-1)
* coefficient is bits 0-4 where
* 0b00000 is the minimum (-4ma) and
* 0b11111 is the maximum (4ma). The
* default 0x 0b01111.
*/
vitesse,txout_driver_ctrl1 = <0x0A0F>;
/* The TX output driver C(0) coefficient
* is bits 8-12 with 0b00000 being the
* minimum (0mA) and 0b11111 being
* the maximum (16mA). The default is
* 0b10011
*
* The C(+1) coefficient is bits 0-5
* with 0b000000 being the minimum
* (-0.25mA) and 0b111111 being the
* maximum (-16mA). The default is
* 0b000000.
*/
/*vitesse,txout_driver_ctrl2 = <0x1300>;*/
/* DC_AGC_LOS_CONFIG1:
* 15: Suppress_Coarse_Adj_on_LOS_Clear
* 0: DC offset correction performed using coarse
* resolution mode (default)
* 1: DC offset correction performed using fine resolution
* mode when correction resumes after LOPC/LOS alarms
* clear. This guarantees there will be no big jumps in
* the offset at the expense of taking longer to reach
* optimal setting.
* 14: Force_DC2_Fine_Adj:
* Forces the DC offset correction to operate in fine
* resolution adjustment mode at times when the algorithm.
* 0: DC offset correction makes coarse adjustments when
* correction mode is first enabled (default)
* 1: DC offset correction performed using fine resolution
* at all times. This is slower.
* 13: Force_DC1_Fine_Adj:
* Forces the DC offset correction to operate in fine
* resolution adjustment mode at times when the algorithm.
* 0: DC offset correction makes coarse adjustments when
* correction mode is first enabled (default)
* 1: DC offset correction performed using fine resolution
* at all times. This is slower.
* 12: Force_DC0_Fine_Adj:
* Forces the DC offset correction to operate in fine
* resolution adjustment mode at times when the algorithm.
* 0: DC offset correction makes coarse adjustments when
* correction mode is first enabled (default)
* 1: DC offset correction performed using fine resolution
* at all times. This is slower.
* 10: Skip_DC2_Adj, 1 = skip DC2 offset correction
* 9: Skip_DC1_Adj, 1 = skip DC1 offset correction
* 8: Skip_DC0_Adj, 1 = skip DC0 offset correction
*
* 6-4: DC_Offset_Alarm_Mode (default 1)
* Selects the alarm condition that will halt the DC offset
* correction logic when the alarm(s) are set.
* 111: reserved
* 110: reserved
* 101: LOPC and software LOS detection
* 100: LOPC and hardware LOS detection
* 011: Software LOS detection
* 010: Hardware LOS detection
* 001: LOPC
* 000: Never. DC offset correction will continue to make
* fine resolution adjustments to the offsets even
* when LOPC and LOS alarms are present.
*
* 3: AGC_Enable
* Selects when hardware AGC adjustment logic and LOS
* detection logic is enabled (default 1)
* 0: disabled
* 1: enabled
* 2: AGC_Suspend
* Suspends the LOS detection logic and AGC logic
* from making adjustments to the gain. Bit valid only
* if AGC_Enable=1
* 0: AGC adjustment enabled (default)
* 1: AGC adjustment suspended
* 1: DC_Offset_Adj_Enable
* Select when the hardware DC offset correction logic is
* enabled.
* 0: disable
* 1: enable (default)
* 0: DC_Offset_Adj_Suspend
* Suspends the DC offset correction logic from making
* adjustments to all offset settings. Bit valid only if
* DC_Offset_Adj_Enable=1
* 0: DC offset correction enabled (default)
* 1: DC offset correction suspended
*
* This setting is only applied for
* passive copper.
*/
vitesse,copper_dc_agc_los_config1 = <0x000A>;
/* Disable aggressive track phase during
* firmware convergence if 0, enabled
* otherwise (default).
*
* This setting is only applied for
* passive copper.
*/
vitesse,copper_agg_track_phase = <0>;
/* AGC_Config4
*
* 13-8: Ampl_Tolerance
* This defines the hysterisis
* built in to the AGC adjustment
* circuit. The VGA gain will not
* be adjusted as long as the
* measured input amplitude is
* Inp_Ampl_Target +/- Amnpl_Tolerance.
* Default is 4.
* 7-0: Inp_Ampl_Target
* This is the target amplitude
* desired to be measured at the
* peak detector when measuring
* input amplitude. The VGA gain
* is adjusted to achieve this
* target setting.
* Default is 0x6E.
*
* This setting is only applied for
* passive copper.
*/
vitesse,copper_agc_config4 = <0x0496>;
/* The Vitesse 10G PHY does not
* automatically read the SFP EEPROM
* so the host needs to do it to put
* the PHY in the proper mode for
* copper or optical.
*/
sfp-eeprom = <&sfp0>;
};
phy1: ethernet-phy@1 {
/* Absolute address */
reg = <0x1>;
compatible = "vitesse,vsc8488", "ethernet-phy-ieee802.3-c45";
interrupt-parent = <&gpio>;
interrupts = <13 8>;
mod_abs = <9>;
/* TX Fault GPIO line */
tx_fault = <8>;
/* GPIO that enables output */
txon = <10>;
/* INT A GPIO output */
inta = <5>;
/* Optional equalization value to
* program into the PHY XS XAUI Rx
* Equalization control register.
* It is broken up into one nibble for
* each lane with lane 0 using bits
* 12 - 15.
* Use the following table:
* 0x0 - 0dB
* 0x1 - 1.41dB
* 0x2 - 2.24dB
* 0x3 - 2.83dB
* 0x5 - 4.48dB
* 0x6 - 5.39dB
* 0x7 - 6.07dB
* 0x9 - 6.18dB
* 0xA - 7.08dB (default)
* 0xB - 7.79dB
* 0xD - 9.96dB
* 0xE - 10.84dB
* 0xF - 11.55dB
*
* This is board specific and should
* only be defined by the hardware
* vendor.
*/
rx_equalization = <0x0000>;
/* Optional transmit pre-emphasis
* control. This sets the
* PHY XS XAUI TX pre-emphasis control
* register.
*
* It uses bits 13-14 for lane 0,
* 10-11 for lane 1, 7-8 for lane 2
* and 4-5 for lane 3.
*
* Bits 2-3 are the LOS threshold
* setting and bit 1 enables
* the XAUI output high swing mode.
*
* Use the following table for
* pre-emphasis:
* 0b00 - 0dB
* 0b01 - 2.5dB
* 0b10 - 6dB (default)
* 0b11 - 12dB
*
* Use the following table for the LOS
* threshold setting:
*
* 0b00 - 50mV - 175mV (default)
* 0b01 - 60mV - 185mV
* 0b10 - 70mV - 195mV
* 0b11 - 80mV - 205mV
*/
tx_preemphasis = <0x0000>;
/* TX output driver slew rate control
* is bits 8-11 where 0x0 is the minimum
* and 0xF is the maximum.
* Default is 0xA.
*
* The TX output driver C(-1)
* coefficient is bits 0-4 where
* 0b00000 is the minimum (-4ma) and
* 0b11111 is the maximum (4ma). The
* default 0x 0b01111.
*/
txout_driver_ctrl1 = <0x0A0F>;
/* The TX output driver C(0) coefficient
* is bits 8-12 with 0b00000 being the
* minimum (0mA) and 0b11111 being
* the maximum (16mA). The default is
* 0b10011
*
* The C(+1) coefficient is bits 0-5
* with 0b000000 being the minimum
* (-0.25mA) and 0b111111 being the
* maximum (-16mA). The default is
* 0b000000.
*/
/*txout_driver_ctrl2 = <0x1300>;*/
/* DC_AGC_LOS_CONFIG1:
* 15: Suppress_Coarse_Adj_on_LOS_Clear
* 0: DC offset correction performed using coarse
* resolution mode (default)
* 1: DC offset correction performed using fine resolution
* mode when correction resumes after LOPC/LOS alarms
* clear. This guarantees there will be no big jumps in
* the offset at the expense of taking longer to reach
* optimal setting.
* 14: Force_DC2_Fine_Adj:
* Forces the DC offset correction to operate in fine
* resolution adjustment mode at times when the algorithm.
* 0: DC offset correction makes coarse adjustments when
* correction mode is first enabled (default)
* 1: DC offset correction performed using fine resolution
* at all times. This is slower.
* 13: Force_DC1_Fine_Adj:
* Forces the DC offset correction to operate in fine
* resolution adjustment mode at times when the algorithm.
* 0: DC offset correction makes coarse adjustments when
* correction mode is first enabled (default)
* 1: DC offset correction performed using fine resolution
* at all times. This is slower.
* 12: Force_DC0_Fine_Adj:
* Forces the DC offset correction to operate in fine
* resolution adjustment mode at times when the algorithm.
* 0: DC offset correction makes coarse adjustments when
* correction mode is first enabled (default)
* 1: DC offset correction performed using fine resolution
* at all times. This is slower.
* 10: Skip_DC2_Adj, 1 = skip DC2 offset correction
* 9: Skip_DC1_Adj, 1 = skip DC1 offset correction
* 8: Skip_DC0_Adj, 1 = skip DC0 offset correction
*
* 6-4: DC_Offset_Alarm_Mode (default 1)
* Selects the alarm condition that will halt the DC offset
* correction logic when the alarm(s) are set.
* 111: reserved
* 110: reserved
* 101: LOPC and software LOS detection
* 100: LOPC and hardware LOS detection
* 011: Software LOS detection
* 010: Hardware LOS detection
* 001: LOPC
* 000: Never. DC offset correction will continue to make
* fine resolution adjustments to the offsets even
* when LOPC and LOS alarms are present.
*
* 3: AGC_Enable
* Selects when hardware AGC adjustment logic and LOS
* detection logic is enabled (default 1)
* 0: disabled
* 1: enabled
* 2: AGC_Suspend
* Suspends the LOS detection logic and AGC logic
* from making adjustments to the gain. Bit valid only
* if AGC_Enable=1
* 0: AGC adjustment enabled (default)
* 1: AGC adjustment suspended
* 1: DC_Offset_Adj_Enable
* Select when the hardware DC offset correction logic is
* enabled.
* 0: disable
* 1: enable (default)
* 0: DC_Offset_Adj_Suspend
* Suspends the DC offset correction logic from making
* adjustments to all offset settings. Bit valid only if
* DC_Offset_Adj_Enable=1
* 0: DC offset correction enabled (default)
* 1: DC offset correction suspended
*
* This setting is only applied for
* passive copper.
*/
vitesse,copper_dc_agc_los_config1 = <0x000A>;
/* Disable aggressive track phase during
* firmware convergence if 0, enabled
* otherwise (default).
*
* This setting is only applied for
* passive copper.
*/
vitesse,copper_agg_track_phase = <0>;
/* AGC_Config4
*
* 13-8: Ampl_Tolerance
* This defines the hysterisis
* built in to the AGC adjustment
* circuit. The VGA gain will not
* be adjusted as long as the
* measured input amplitude is
* Inp_Ampl_Target +/- Amnpl_Tolerance.
* Default is 4.
* 7-0: Inp_Ampl_Target
* This is the target amplitude
* desired to be measured at the
* peak detector when measuring
* input amplitude. The VGA gain
* is adjusted to achieve this
* target setting.
* Default is 0x6E.
*
* This setting is only applied for
* passive copper.
*/
vitesse,copper_agc_config4 = <0x0496>;
/* The Vitesse 10G PHY does not
* automatically read the SFP EEPROM
* so the host needs to do it to put
* the PHY in the proper mode for
* copper or optical.
*/
sfp-eeprom = <&sfp1>;
};
};
mphyB: ethernet-phy-nexus@B {
reg = <0>;
/* The TI TLK10232 is a dual-PHY where
* some of the configuration is common across
* both of the phy devices such as the reset
* line and the base MDIO address.
*/
compatible = "ti,tlk10232-nexus", "ethernet-phy-nexus";
#address-cells = <1>;
#size-cells = <0>;
ranges;
cavium,phy-trim = "0,ti";
/* Hardware reset signal open-drain active low on GPIO 17, must not be driven high. */
reset = <&gpio 17 2>;
phy11: ethernet-phy@0 {
/* Absolute address */
reg = <0>;
compatible = "ti,tlk10232", "ethernet-phy-ieee802.3-c45";
/* The TI 10G PHY does not
* automatically read the SFP EEPROM
* so the host needs to do it to put
* the PHY in the proper mode for
* copper or optical.
*/
sfp-eeprom = <&sfp0>;
/* TX fault input signal for PHY from SFP+ */
tx-fault = <&gpio1 4 0>;
/* TX disable for PHY to SFP+ */
tx-disable = <&gpio1 5 0>;
/* MOD ABS signal for PHY from SFP+ */
mod-abs = <&gpio1 6 0>;
/* RX los of singal for PHY from SFP+ */
rx-los = <&gpio1 7 0>;
};
phy10: ethernet-phy@1 {
/* Absolute address */
reg = <0x1>;
compatible = "ti,tlk10232", "ethernet-phy-ieee802.3-c45";
/* The TI 10G PHY does not
* automatically read the SFP EEPROM
* so the host needs to do it to put
* the PHY in the proper mode for
* copper or optical.
*/
sfp-eeprom = <&sfp1>;
/* TX fault input signal for PHY */
tx-fault = <&gpio1 0 0>;
/* TX disable for PHY */
tx-disable = <&gpio1 1 0>;
/* MOD ABS signal for PHY */
mod-abs = <&gpio1 2 0>;
/* RX los of singal for PHY */
rx-los = <&gpio1 3 0>;
};
};
};
pip: pip@11800a0000000 {
compatible = "cavium,octeon-3860-pip";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x11800 0xa0000000 0x0 0x2000>;
interface@A {
compatible = "cavium,octeon-3860-pip-interface";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>; /* interface */
cavium,phy-trim = "0,vitesse";
ethernet@0 {
compatible = "cavium,octeon-3860-pip-port";
reg = <0x0>; /* Port */
local-mac-address = [ 00 00 00 00 00 00 ];
phy-handle = <&phy0>;
};
};
interface@B {
compatible = "cavium,octeon-3860-pip-interface";
#address-cells = <1>;
#size-cells = <0>;
reg = <1>; /* interface */
cavium,phy-trim = "0,vitesse";
ethernet@0 {
compatible = "cavium,octeon-3860-pip-port";
reg = <0x0>; /* Port */
local-mac-address = [ 00 00 00 00 00 00 ];
phy-handle = <&phy1>;
};
};
interface@C {
compatible = "cavium,octeon-3860-pip-interface";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>; /* interface */
cavium,phy-trim = "0,ti";
ethernet@0 {
compatible = "cavium,octeon-3860-pip-port";
reg = <0x0>; /* Port */
local-mac-address = [ 00 00 00 00 00 00 ];
phy-handle = <&phy10>;
};
};
interface@D {
compatible = "cavium,octeon-3860-pip-interface";
#address-cells = <1>;
#size-cells = <0>;
reg = <1>; /* interface */
cavium,phy-trim = "0,ti";
ethernet@0 {
compatible = "cavium,octeon-3860-pip-port";
reg = <0x0>; /* Port */
local-mac-address = [ 00 00 00 00 00 00 ];
phy-handle = <&phy11>;
};
};
};
uart0: serial@1180000000800 {
compatible = "cavium,octeon-3860-uart","ns16550";
reg = <0x11800 0x00000800 0x0 0x400>;
clock-frequency = <400000000>;
current-speed = <115200>;
reg-shift = <3>;
interrupts = <0 34>;
};
uart1: serial@1180000000c00 {
compatible = "cavium,octeon-3860-uart","ns16550";
reg = <0x11800 0x00000c00 0x0 0x400>;
clock-frequency = <400000000>;
current-speed = <115200>;
reg-shift = <3>;
interrupts = <0 35>;
};
bootbus: bootbus@1180000000000 {
compatible = "cavium,octeon-3860-bootbus";
reg = <0x11800 0x00000000 0x0 0x200>;
/* The chip select number and offset */
#address-cells = <2>;
/* The size of the chip select region */
#size-cells = <1>;
ranges = <0 0 0 0x1f400000 0xc00000>,
<1 0 0x10000 0x30000000 0>,
<2 0 0 0x1f000000 0x100000>,
<3 0 0x10000 0x50000000 0>,
<4 0 0x10000 0x60000000 0>,
<5 0 0x10000 0x70000000 0>,
<6 0 0x10000 0x80000000 0>,
<7 0 0x10000 0x90000000 0>;
cavium,cs-config@0 {
compatible = "cavium,octeon-3860-bootbus-config";
cavium,cs-index = <0>;
cavium,t-adr = <10>;
cavium,t-ce = <50>;
cavium,t-oe = <50>;
cavium,t-we = <35>;
cavium,t-rd-hld = <25>;
cavium,t-wr-hld = <35>;
cavium,t-pause = <0>;
cavium,t-wait = <300>;
cavium,t-page = <25>;
cavium,t-rd-dly = <0>;
cavium,pages = <0>;
cavium,bus-width = <8>;
};
cavium,cs-config@2 {
compatible = "cavium,octeon-3860-bootbus-config";
cavium,cs-index = <2>;
cavium,t-adr = <0>;
cavium,t-ce = <50>;
cavium,t-oe = <20>;
cavium,t-we = <46>;
cavium,t-rd-hld = <8>;
cavium,t-wr-hld = <10>;
cavium,t-pause = <0>;
cavium,t-wait = <0>;
cavium,t-page = <1>;
cavium,t-ale = <1>;
cavium,t-rd-dly = <0>;
cavium,pages = <0>;
cavium,bus-width = <8>;
};
flash0: nor@0,0 {
compatible = "cfi-flash";
reg = <0 0 0x800000>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "bootloader";
reg = <0x0 0x1c0000>;
read-only;
};
partition@1c0000 {
label = "kernel";
reg = <0x1c0000 0x63e000>;
};
partition@7fe000 {
label = "environment";
reg = <0x7fe0000 0x2000>;
read-only;
};
};
psram0: psram@2,0 {
compatible = "micron,mt45w1mw16pd";
reg = <2 0x20 0x20>, <2 0 0x20>;
};
};
dma0: dma-engine@1180000000100 {
compatible = "cavium,octeon-5750-bootbus-dma";
reg = <0x11800 0x00000100 0x0 0x8>;
interrupts = <0 63>;
};
dma1: dma-engine@1180000000108 {
compatible = "cavium,octeon-5750-bootbus-dma";
reg = <0x11800 0x00000108 0x0 0x8>;
interrupts = <0 63>;
};
nand-flash-interface@1070001000000 {
compatible = "cavium,octeon-5230-nand";
reg = <0x10700 0x1000000 0x0 0x100 0x11800 0x168 0x0 0x20>;
#address-cells = <0x1>;
#size-cells = <0x0>;
interrupts = <0x0 0x3f>;
flash@1 {
compatible = "nand-flash";
reg = <0x1>;
nand-ecc-mode = "soft";
nand-ecc-size = <0x200>;
nand-ecc-bytes = <0x7>;
nand-bus-width = <0x8>;
};
};
};
gpio-leds {
compatible = "gpio-leds";
d1a {
label = "bottom";
gpios = <&gpio 1 0>;
default-state = "keep";
cavium,phy-trim = "0,ti";
};
d1b-t {
label = "top";
gpios = <&gpio 2 0>;
default-state = "keep";
cavium,phy-trim = "0,ti";
};
d1b-v {
label = "top";
gpios = <&gpio 2 0>;
default-state = "keep";
cavium,phy-trim = "0,vitesse";
};
};
aliases {
pip = &pip;
smi0 = &smi0;
twsi0 = &twsi0;
twsi1 = &twsi1;
uart0 = &uart0;
uart1 = &uart1;
flash0 = &flash0;
};
};

View File

@ -65,6 +65,16 @@ define Device/ubnt_edgerouter-4
endef
TARGET_DEVICES += ubnt_edgerouter-4
define Device/snic10e
DEVICE_VENDOR := Cavium
DEVICE_MODEL := snic10e
DEVICE_DTS := snic10e
DEVICE_PACKAGES += kmod-gpio-button-hotplug kmod-leds-gpio kmod-of-mdio kmod-sfp kmod-usb3 kmod-usb-storage-uas
KERNEL := kernel-bin | append-dtb-to-elf
KERNEL_DEPENDS := $$(wildcard $(DTS_DIR)/$(DEVICE_DTS).dts)
endef
TARGET_DEVICES += snic10e
ERLITE_CMDLINE:=-mtdparts=phys_mapped_flash:512k(boot0)ro,512k(boot1)ro,64k(eeprom)ro root=/dev/sda2 rootfstype=squashfs,ext4 rootwait
define Device/ubnt_edgerouter-lite
DEVICE_VENDOR := Ubiquiti

View File

@ -0,0 +1,829 @@
From: Abhishek Paliwal <abhishek.paliwal@aricent.com>
Date: Fri, 13 Feb 2015 15:04:55 +0530
Subject: netdev/phy: Add driver for Vitesse vsc848x single, dual and quad 10G
phys
From: David Daney <david.daney@cavium.com>
These phys implement the standard IEEE 802.3 clause 45 registers but
require additional configuration. Some of these registers in the multi-phy
devices are shared among all phys such as the GPIO registers.
Additionally, this PHY does not automatically access the SFP+ serial EEPROM so
it is up to the PHY driver to parse it and change certain parameters in the
PHY according to the type of module installed and the length of the cable, if
copper.
This module has support for the vsc8488, vsc8486 and vsc8484 Vitesse devices
but thus far has only been tested with the vsc8488 dual PHY.
netdev/phy: Clean up structure names in vsc848x.c
Cut-and-paste snafu left some bad names, no functional change.
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Aaron Williams <aaron.williams@cavium.com>
Signed-off-by: Leonid Rosenboim <lrosenboim@caviumnetworks.com>
Signed-off-by: Abhishek Paliwal <abhishek.paliwal@aricent.com>
[Rebased on kernel 5.4 by Martin Kennedy <hurricos@gmail.com>]
Signed-off-by: Martin Kennedy <hurricos@gmail.com>
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -54,6 +54,13 @@ config VITESSE_PHY
---help---
Currently supports the vsc8244
+config VSC848X_PHY
+ tristate "Drivers for the Vitesse 10G PHYs"
+ depends on OF_MEMORY_ACCESSOR
+ help
+ Driver for Vitesse vsc848x single, dual and quad 10G PHY devices.
+ Currently supports the vsc8488, vsc8486 and vsc8484 chips
+
config SMSC_PHY
tristate "Drivers for SMSC PHYs"
---help---
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -108,4 +108,5 @@
obj-$(CONFIG_STE10XP) += ste10Xp.o
obj-$(CONFIG_TERANETICS_PHY) += teranetics.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
+obj-$(CONFIG_VSC848X_PHY) += vsc848x.o
obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
--- /dev/null
+++ b/drivers/net/phy/vsc848x.c
@@ -0,0 +1,774 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 Cavium, Inc.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/of_mdio.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/phy.h>
+#include <linux/memory.h>
+#include <linux/mutex.h>
+#include <linux/of_memory_accessor.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+
+#define PMD_RX_SIGNAL_DETECT (MII_ADDR_C45 | 0x01000a)
+#define PMA_TXOUTCTRL2 (MII_ADDR_C45 | 0x018014)
+#define EDC_EYE_QUALITY (MII_ADDR_C45 | 0x018034)
+/* EDC Firmware State Machine Status and Lib Force
+ * 15: library force enable
+ * 14:8 - Library number
+ * 7:5 - N/A
+ * 4 - State force
+ * 3:0 - FW state (1=reset, 2=wait for alarm to clear, 3 = convergence,
+ * 4 = tracking, 5 = freeze)
+ */
+#define EDC_FW_SM_STATUS (MII_ADDR_C45 | 0x018036)
+
+#define BASER_PCS_STATUS (MII_ADDR_C45 | 0x030020)
+#define XGXS_LANE_STATUS (MII_ADDR_C45 | 0x040018)
+#define EWIS_INTR_PEND1 (MII_ADDR_C45 | 0x02EE00)
+#define EWIS_INTR_MASKA_1 (MII_ADDR_C45 | 0x02EE01)
+#define EWIS_INTR_MASKB_1 (MII_ADDR_C45 | 0x02EE02)
+#define EWIS_INTR_STAT2 (MII_ADDR_C45 | 0x02EE03)
+#define EWIS_INTR_PEND2 (MII_ADDR_C45 | 0x02EE04)
+#define EWIS_INTR_MASKA_2 (MII_ADDR_C45 | 0x02EE05)
+#define EWIS_INTR_MASKB_2 (MII_ADDR_C45 | 0x02EE06)
+#define EWIS_FAULT_MASK (MII_ADDR_C45 | 0x02EE07)
+#define EWIS_INTR_PEND3 (MII_ADDR_C45 | 0x02EE08)
+#define EWIS_INTR_MASKA_3 (MII_ADDR_C45 | 0x02EE09)
+#define EWIS_INTR_MASKB_3 (MII_ADDR_C45 | 0x02EE0A)
+
+/* Device ID
+ * 15:0 - device ID
+ */
+#define GBL_DEVICE_ID (MII_ADDR_C45 | 0x1e0000)
+/* Device revision
+ * 15:04 - reserved
+ * 03:00 - revision ID
+ */
+#define GBL_DEVICE_REVISION (MII_ADDR_C45 | 0x1e0001)
+/* Block Level Software Reset
+ * 15:14 - reserved
+ * 13: - software reset EDC 1 (1 = reset, autoclears)
+ * 12: - software reset EDC 0 (1 = reset, autoclears)
+ * 11:10 - reserved
+ * 09: - Software reset channel 1 (1 = reset, autoclears)
+ * 08: - Software reset channel 0 (1 = reset, autoclears)
+ * 07: - Microprocessor reset (0 = normal operation, 1 = reset)
+ * 06: - Software reset BIU (1 = reset, autoclears)
+ * 05: - Software reset TWS slave (1 = reset, autoclears)
+ * 04: - Software reset TWS master (1 = reset, autoclears)
+ * 03: - Software reset MDIO (1 = reset, autoclears)
+ * 02: - Software reset UART (1 = reset, autoclears)
+ * 01: - Global register reset (1 = reset, autoclears)
+ * 00: - Software reset chip (1 = reset, autoclears)
+ */
+#define GBL_BLOCK_LVL_SW_RESET (MII_ADDR_C45 | 0x1e0002)
+#define GBL_GPIO_0_CONFIG1_STATUS (MII_ADDR_C45 | 0x1e0100)
+#define GBL_GPIO_0_CONFIG2 (MII_ADDR_C45 | 0x1e0101)
+#define GBL_DEVICE_ID (MII_ADDR_C45 | 0x1e0000)
+#define GBL_FW_CHECKSUM (MII_ADDR_C45 | 0x1e7fe0)
+#define GBL_FW_WATCHDOG (MII_ADDR_C45 | 0x1e7fe1)
+#define GBL_FW_VERSION (MII_ADDR_C45 | 0x1e7fe2)
+#define GBL_FW_VAR_ACC_CTRL (MII_ADDR_C45 | 0x1e7fe3)
+#define GBL_FW_VAR_ACC_DATA (MII_ADDR_C45 | 0x1e7fe4)
+
+/* The Vitesse VSC848X series are 10G PHYs.
+ *
+ * Some of these devices contain multiple PHYs in a single package and
+ * some features are controlled by a global set of registers shared between
+ * all of the PHY devices. Because of this a nexus is used to handle all
+ * of the PHYs on the same device.
+ *
+ * Unlike some PHY devices, it is up to the driver to read the SFP module
+ * serial EEPROM in order to put the PHY into the right mode. The VSC848X
+ * does not provide an I2C interface so the PHY driver relies on the
+ * external AT24 I2C EEPROM driver to read the module whenever it is inserted.
+ *
+ */
+
+/* Enable LOPC detection (see 0x5B for target state)
+ * 15:12 - channel 3
+ * 11:08 - channel 2
+ * 07:04 - channel 1
+ * 03:00 - channel 0
+ * 1 = enable (default), 0 = disable
+ */
+#define FW_VAR_ENABLE_LOPC 0x58
+/* While in tracking mode, go to this state in response to LOPC assertion
+ * 1 = reset, 2 = wait (default), 3 = converging, 4 = tracking, 5 = freeze
+ */
+#define FW_VAR_LOPC_ASSERT_MODE 0x5B
+/* While in freeze mode, enable state transition upon deassertion of LOPC (see
+ * 0x61 for target state)
+ * 1 - reset, 2 = wait, 3 = converging, 4 = tracking (default), 5 = freeze
+ */
+#define FW_VAR_FREEZE_DEASSERT_MODE 0x61
+/* Current functional mode
+ * See VITESSE_FUNC_MODE_XXX below for values
+ * NOTE: When the firmware is done servicing the mode change request, bit 4
+ * will be set to 1.
+ */
+#define FW_VAR_FUNCTIONAL_MODE 0x94
+/* Current state of graded SPSA process
+ * 3: channel 3
+ * 2: channel 2
+ * 1: channel 1
+ * 0: channel 0
+ * 1 = busy, 2 = done
+ */
+#define FW_VAR_GRADED_SPSA_STATE 0x95
+/* BerScore at start of SPSA cycle */
+#define FW_VAR_BERSCORE_START 0x96
+/* BerScore at end of SPSA cycle */
+#define FW_VAR_BERSCORE_END 0x97
+/* Enable/Disable aggressive track phase on entering tracking state
+ * 15:12 - channel 3
+ * 11:08 - channel 2
+ * 07:04 - channel 1
+ * 03:00 - channel 0
+ * 0 = disable, 1 = enable (default)
+ */
+#define FW_VAR_AGG_TRACKING 0xAF
+
+/* Modes for the PHY firmware */
+#define VITESSE_FUNC_MODE_LIMITING 2 /* Optical */
+#define VITESSE_FUNC_MODE_COPPER 3 /* Copper */
+#define VITESSE_FUNC_MODE_LINEAR 4
+#define VITESSE_FUNC_MODE_KR 5
+#define VITESSE_FUNC_MODE_ZR 7
+#define VITESSE_FUNC_MODE_1G 8
+
+
+struct vsc848x_nexus_mdiobus {
+ struct mii_bus *mii_bus;
+ struct mii_bus *parent_mii_bus;
+ int reg_offset;
+ struct mutex lock; /* Lock used for global register sequences */
+ int phy_irq[PHY_MAX_ADDR];
+};
+
+struct vsc848x_phy_info {
+ int sfp_conn; /* Module connected? */
+ int tx_en_gpio; /* GPIO that enables transmit */
+ int mod_abs_gpio; /* Module Absent GPIO line */
+ int tx_fault_gpio; /* TX Fault GPIO line */
+ int inta_gpio, intb_gpio; /* Interrupt GPIO line (output) */
+ uint8_t mode; /* Mode for module */
+ uint8_t channel; /* channel in multi-phy devices */
+ struct device_node *sfp_node; /* EEPROM NODE for SFP */
+ struct memory_accessor *macc; /* memory access routines for EEPROM */
+ struct vsc848x_nexus_mdiobus *nexus; /* Nexus for lock */
+};
+
+/**
+ * Maps GPIO lines to the global GPIO config registers.
+ *
+ * Please see the data sheet since the configuration for each GPIO line is
+ * different.
+ */
+static const struct {
+ uint32_t config1_status_reg;
+ uint32_t config2_reg;
+} vcs848x_gpio_to_reg[12] = {
+ { (MII_ADDR_C45 | 0x1e0100), (MII_ADDR_C45 | 0x1e0101) }, /* 0 */
+ { (MII_ADDR_C45 | 0x1e0102), (MII_ADDR_C45 | 0x1e0103) }, /* 1 */
+ { (MII_ADDR_C45 | 0x1e0104), (MII_ADDR_C45 | 0x1e0105) }, /* 2 */
+ { (MII_ADDR_C45 | 0x1e0106), (MII_ADDR_C45 | 0x1e0107) }, /* 3 */
+ { (MII_ADDR_C45 | 0x1e0108), (MII_ADDR_C45 | 0x1e0109) }, /* 4 */
+ { (MII_ADDR_C45 | 0x1e010A), (MII_ADDR_C45 | 0x1e010B) }, /* 5 */
+ { (MII_ADDR_C45 | 0x1e0124), (MII_ADDR_C45 | 0x1e0125) }, /* 6 */
+ { (MII_ADDR_C45 | 0x1e0126), (MII_ADDR_C45 | 0x1e0127) }, /* 7 */
+ { (MII_ADDR_C45 | 0x1e0128), (MII_ADDR_C45 | 0x1e0129) }, /* 8 */
+ { (MII_ADDR_C45 | 0x1e012a), (MII_ADDR_C45 | 0x1e012b) }, /* 9 */
+ { (MII_ADDR_C45 | 0x1e012c), (MII_ADDR_C45 | 0x1e012d) }, /* 10 */
+ { (MII_ADDR_C45 | 0x1e012e), (MII_ADDR_C45 | 0x1e012f) }, /* 11 */
+};
+
+static int vsc848x_probe(struct phy_device *phydev)
+{
+ struct vsc848x_phy_info *dev_info;
+ int ret;
+
+ dev_info = devm_kzalloc(&phydev->dev, sizeof(*dev_info), GFP_KERNEL);
+ if (dev_info == NULL)
+ return -ENOMEM;
+
+ phydev->priv = dev_info;
+ dev_info->mode = VITESSE_FUNC_MODE_LIMITING; /* Default to optical */
+ phydev->priv = dev_info;
+ dev_info->nexus = phydev->bus->priv;
+
+ ret = of_property_read_u32(phydev->dev.of_node, "mod_abs",
+ &dev_info->mod_abs_gpio);
+ if (ret) {
+ dev_err(&phydev->dev, "%s has invalid mod_abs address\n",
+ phydev->dev.of_node->full_name);
+ return ret;
+ }
+
+ ret = of_property_read_u32(phydev->dev.of_node, "tx_fault",
+ &dev_info->tx_fault_gpio);
+ if (ret) {
+ dev_err(&phydev->dev, "%s has invalid tx_fault address\n",
+ phydev->dev.of_node->full_name);
+ return ret;
+ }
+
+ ret = of_property_read_u32(phydev->dev.of_node, "inta",
+ &dev_info->inta_gpio);
+ if (ret)
+ dev_info->inta_gpio = -1;
+
+ ret = of_property_read_u32(phydev->dev.of_node, "intb",
+ &dev_info->intb_gpio);
+ if (ret)
+ dev_info->intb_gpio = -1;
+
+ ret = of_property_read_u32(phydev->dev.of_node, "txon",
+ &dev_info->tx_en_gpio);
+ if (ret) {
+ dev_err(&phydev->dev, "%s has invalid txon gpio address\n",
+ phydev->dev.of_node->full_name);
+ return -ENXIO;
+ }
+
+ dev_info->sfp_node = of_parse_phandle(phydev->dev.of_node,
+ "sfp-eeprom", 0);
+ if (!dev_info->sfp_node) {
+ dev_err(&phydev->dev, "%s has invalid sfp-eeprom node\n",
+ phydev->dev.of_node->full_name);
+ return -ENXIO;
+ }
+
+ dev_info->macc = of_memory_accessor_get(dev_info->sfp_node);
+
+ ret = phy_read(phydev, GBL_DEVICE_ID);
+ if (ret < 0) {
+ dev_err(&phydev->dev, "%s error reading PHY\n",
+ phydev->dev.of_node->full_name);
+ return ret;
+ }
+
+ /* Check how many devices are in the package to figure out the channel
+ * number.
+ */
+ switch (ret) {
+ case 0x8487: /* Single */
+ case 0x8486:
+ dev_info->channel = 0;
+ break;
+ case 0x8488: /* Dual */
+ dev_info->channel = phydev->addr & 1;
+ break;
+ case 0x8484: /* Quad */
+ dev_info->channel = phydev->addr & 3;
+ break;
+ default:
+ dev_err(&phydev->dev, "%s Unknown Vitesse PHY model %04x\n",
+ phydev->dev.of_node->full_name, ret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void vsc848x_remove(struct phy_device *phydev)
+{
+ struct vsc848x_phy_info *dev_info = phydev->priv;
+
+ dev_info(&phydev->dev, "%s Exiting\n", phydev->dev.of_node->full_name);
+
+ of_memory_accessor_put(dev_info->sfp_node);
+
+ kfree(dev_info);
+}
+
+static int vsc848x_config_init(struct phy_device *phydev)
+{
+ phydev->supported = SUPPORTED_10000baseR_FEC;
+ phydev->advertising = ADVERTISED_10000baseR_FEC;
+ phydev->state = PHY_NOLINK;
+
+ return 0;
+}
+
+static int vsc848x_config_aneg(struct phy_device *phydev)
+{
+ return -EINVAL;
+}
+
+static int vsc848x_write_global_var(struct phy_device *phydev, uint8_t channel,
+ uint8_t addr, uint16_t value)
+{
+ struct vsc848x_phy_info *dev_info = phydev->priv;
+ int timeout = 1000;
+ int ret = 0;
+
+ mutex_lock(&(dev_info->nexus->lock));
+
+ /* Wait for firmware download to complete */
+ timeout = 100000;
+ do {
+ ret = phy_read(phydev, MII_ADDR_C45 | 0x1e7fe0);
+ if (ret < 0)
+ goto error;
+ if (ret == 3)
+ break;
+ udelay(100);
+ } while (timeout-- > 0);
+ if (timeout <= 0) {
+ dev_err(&phydev->dev, "%s Timeout waiting for PHY firmware to load\n",
+ phydev->dev.of_node->full_name);
+ ret = -EIO;
+ goto error;
+ }
+
+ do {
+ ret = phy_read(phydev, (MII_ADDR_C45 | 0x1e7fe3));
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ break;
+ mdelay(1);
+ } while (timeout-- > 0);
+ if (timeout <= 0) {
+ dev_err(&phydev->dev, "%s timed out waiting to write global\n",
+ phydev->dev.of_node->full_name);
+ ret = -EIO;
+ goto error;
+ }
+ ret = phy_write(phydev, (MII_ADDR_C45 | 0x1e7fe4), value);
+ if (ret < 0)
+ goto error;
+
+ ret = phy_write(phydev, (MII_ADDR_C45 | 0x1e7fe3),
+ 0x8000 | ((channel & 3) << 8) | addr);
+ if (ret < 0)
+ goto error;
+
+ /* Wait for value to be written */
+ do {
+ ret = phy_read(phydev, (MII_ADDR_C45 | 0x1e7fe3));
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ break;
+ mdelay(1);
+ } while (timeout-- > 0);
+ if (timeout <= 0) {
+ dev_err(&phydev->dev, "%s timed out waiting to write global\n",
+ phydev->dev.of_node->full_name);
+ ret = -EIO;
+ goto error;
+ }
+ ret = 0;
+
+error:
+ mutex_unlock(&(dev_info->nexus->lock));
+
+ return ret;
+}
+
+/**
+ * Dumps out the contents of the SFP EEPROM when errors are detected
+ *
+ * @param eeprom - contents of SFP+ EEPROM
+ */
+static void dump_sfp_eeprom(const uint8_t eeprom[64])
+{
+ int addr = 0;
+ int i;
+ char line[17];
+ line[16] = '\0';
+
+ pr_info("SFP+ EEPROM contents:\n");
+ while (addr < 64) {
+ pr_info(" %02x: ", addr);
+ for (i = 0; i < 16; i++)
+ pr_cont("%02x ", eeprom[addr + i]);
+ for (i = 0; i < 16; i++) {
+ if (!isprint(eeprom[addr + i]) ||
+ eeprom[addr + i] >= 0x80)
+ line[i] = '.';
+ else
+ line[i] = eeprom[addr + i];
+ }
+ pr_cont(" %s\n", line);
+ addr += 16;
+ }
+ pr_info("\n");
+}
+
+/**
+ * Read the SFP+ module EEPROM and program the Vitesse PHY accordingly.
+ *
+ * @param phydev - Phy device
+ *
+ * @returns 0 for success, error otherwise.
+ */
+static int vsc848x_read_sfp(struct phy_device *phydev)
+{
+ struct vsc848x_phy_info *dev_info = phydev->priv;
+ uint8_t sfp_buffer[64];
+ ssize_t size;
+ uint8_t csum;
+ uint8_t mode = VITESSE_FUNC_MODE_LIMITING;
+ const char *mode_str = "Unknown";
+ int i;
+ int ret = 0;
+
+ /* For details on the SFP+ EEPROM contents see the SFF-8472
+ * Diagnostic Monitoring Interface for Optical Transceivers.
+ *
+ * This is based on revision 11.1, October 26, 2012.
+ */
+ if (!dev_info->macc) {
+ dev_info->macc = of_memory_accessor_get(dev_info->sfp_node);
+ if (!dev_info->macc) {
+ dev_info(&phydev->dev,
+ "Could not connect to sfp memory accessor %s\n",
+ dev_info->sfp_node->full_name);
+ return -ENODEV;
+ }
+ }
+ size = dev_info->macc->read(dev_info->macc,
+ (char *)sfp_buffer, 0, sizeof(sfp_buffer));
+ if (size != sizeof(sfp_buffer)) {
+ dev_err(&phydev->dev, "%s cannot read SFP module EEPROM\n",
+ phydev->dev.of_node->full_name);
+ return -ENODEV;
+ }
+
+ /* Validate SFP checksum */
+ csum = 0;
+ for (i = 0; i < 63; i++)
+ csum += sfp_buffer[i];
+ if (csum != sfp_buffer[63]) {
+ dev_err(&phydev->dev, "%s SFP EEPROM checksum bad, calculated 0x%02x, should be 0x%02x\n",
+ phydev->dev.of_node->full_name, csum, sfp_buffer[63]);
+ dump_sfp_eeprom(sfp_buffer);
+ return -ENXIO;
+ }
+
+ /* Make sure it's a SFP or SFP+ module */
+ if (sfp_buffer[0] != 3) {
+ dev_err(&phydev->dev, "%s module is not SFP or SFP+\n",
+ phydev->dev.of_node->full_name);
+ dump_sfp_eeprom(sfp_buffer);
+ return -ENXIO;
+ }
+
+ /* Check connector type */
+ switch (sfp_buffer[2]) {
+ case 0x01: /* SC */
+ mode = VITESSE_FUNC_MODE_LIMITING;
+ break;
+ case 0x07: /* LC */
+ mode = VITESSE_FUNC_MODE_LIMITING;
+ break;
+ case 0x0B: /* Optical pigtail */
+ mode = VITESSE_FUNC_MODE_LIMITING;
+ break;
+ case 0x21: /* Copper pigtail */
+ case 0x22: /* RJ45 */
+ mode = VITESSE_FUNC_MODE_COPPER;
+ break;
+ default:
+ dev_err(&phydev->dev, "%s Unknown Connector Type 0x%x\n",
+ phydev->dev.of_node->full_name, sfp_buffer[2]);
+ dump_sfp_eeprom(sfp_buffer);
+ return -EINVAL;
+ }
+
+ if (mode == VITESSE_FUNC_MODE_LIMITING) {
+ if (mode_str[3] & 0x10)
+ mode_str = "10GBase-SR";
+ else if (mode_str[3] & 0x20)
+ mode_str = "10GBase-LR";
+ else if (mode_str[3] & 0x40)
+ mode_str = "10GBase-LRM";
+ else if (mode_str[3] & 0x80)
+ mode_str = "10GBase-ER";
+ else
+ dev_err(&phydev->dev, "%s unknown SFP compatibility\n"
+ "type ID: 0x%02x, extended ID: 0x%02x, Connector type code: 0x%02x\n"
+ "Transceiver compatibility code: (%02x) %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ phydev->dev.of_node->full_name, sfp_buffer[0],
+ sfp_buffer[1], sfp_buffer[2], sfp_buffer[36],
+ sfp_buffer[3], sfp_buffer[4], sfp_buffer[5],
+ sfp_buffer[6], sfp_buffer[7], sfp_buffer[8],
+ sfp_buffer[9], sfp_buffer[10]);
+ } else if (mode == VITESSE_FUNC_MODE_COPPER) {
+ if (sfp_buffer[8] & 0x4) {
+ mode_str = "10G Passive Copper";
+ } else if (sfp_buffer[8] & 0x8) {
+ mode_str = "10G Active Copper";
+ mode = VITESSE_FUNC_MODE_LIMITING;
+ } else {
+ dev_err(&phydev->dev, "%s Unknown SFP+ copper cable capability 0x%02x\n"
+ "Transceiver compatibility code: (%02x) %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ phydev->dev.of_node->full_name, sfp_buffer[8],
+ sfp_buffer[36], sfp_buffer[3], sfp_buffer[4],
+ sfp_buffer[5], sfp_buffer[6], sfp_buffer[7],
+ sfp_buffer[8], sfp_buffer[9], sfp_buffer[10]);
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&phydev->dev, "%s Unsupported phy mode %d\n",
+ phydev->dev.of_node->full_name, mode);
+ dump_sfp_eeprom(sfp_buffer);
+ }
+
+ vsc848x_write_global_var(phydev, dev_info->channel, 0x94, mode);
+
+ /* Adjust PMA_TXOUTCTRL2 based on cable length. Vitesse recommends
+ * 0x1606 for copper cable lengths 5M and longer.
+ *
+ * The default value is 0x1300.
+ */
+ if (mode == VITESSE_FUNC_MODE_COPPER) {
+ if (sfp_buffer[18] >= 5)
+ ret = phy_write(phydev, PMA_TXOUTCTRL2, 0x1606);
+ else
+ ret = phy_write(phydev, PMA_TXOUTCTRL2, 0x1300);
+ if (ret)
+ return ret;
+ }
+
+ /* Reset the state machine */
+ ret = phy_write(phydev, MII_ADDR_C45 | 0x18034, 0x11);
+
+ dev_info(&phydev->dev, "%s configured for %s\n",
+ phydev->dev.of_node->full_name, mode_str);
+
+ return ret;
+}
+
+static int vsc848x_read_status(struct phy_device *phydev)
+{
+ struct vsc848x_phy_info *dev_info = phydev->priv;
+ int rx_signal_detect;
+ int pcs_status;
+ int xgxs_lane_status;
+ int value;
+ int sfp_conn;
+ int ret;
+
+ /* Check if a module is plugged in */
+ value = phy_read(phydev, vcs848x_gpio_to_reg[dev_info->mod_abs_gpio]
+ .config1_status_reg);
+ if (value < 0)
+ return value;
+
+ sfp_conn = !(value & 0x400);
+
+ if (sfp_conn != dev_info->sfp_conn) {
+ /* We detect a module being plugged in */
+ if (sfp_conn) {
+ ret = vsc848x_read_sfp(phydev);
+ if (ret < 0)
+ goto no_link;
+ dev_info->sfp_conn = sfp_conn;
+ } else {
+ dev_info(&phydev->dev, "%s module unplugged\n",
+ phydev->dev.of_node->full_name);
+ dev_info->sfp_conn = sfp_conn;
+ goto no_link;
+ }
+ }
+
+ rx_signal_detect = phy_read(phydev, PMD_RX_SIGNAL_DETECT);
+ if (rx_signal_detect < 0)
+ return rx_signal_detect;
+
+ if ((rx_signal_detect & 1) == 0)
+ goto no_link;
+
+ pcs_status = phy_read(phydev, BASER_PCS_STATUS);
+ if (pcs_status < 0)
+ return pcs_status;
+
+ if ((pcs_status & 1) == 0)
+ goto no_link;
+
+ xgxs_lane_status = phy_read(phydev, XGXS_LANE_STATUS);
+ if (xgxs_lane_status < 0)
+ return xgxs_lane_status;
+
+ if ((xgxs_lane_status & 0x1000) == 0)
+ goto no_link;
+
+ phydev->speed = 10000;
+ phydev->link = 1;
+ phydev->duplex = 1;
+ return 0;
+no_link:
+ phydev->link = 0;
+ return 0;
+}
+
+static struct of_device_id vsc848x_match[] = {
+ {
+ .compatible = "vitesse,vsc8488",
+ },
+ {
+ .compatible = "vitesse,vsc8486",
+ },
+ {
+ .compatible = "vitesse,vsc8484",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, vsc848x_match);
+
+static struct phy_driver vsc848x_phy_driver = {
+ .phy_id = 0x00070400,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Vitesse VSC848X",
+ .config_init = vsc848x_config_init,
+ .probe = vsc848x_probe,
+ .remove = vsc848x_remove,
+ .config_aneg = vsc848x_config_aneg,
+ .read_status = vsc848x_read_status,
+ .driver = {
+ .owner = THIS_MODULE,
+ .of_match_table = vsc848x_match,
+ },
+};
+
+/* Phy nexus support below. */
+
+static int vsc848x_nexus_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+ struct vsc848x_nexus_mdiobus *p = bus->priv;
+ return p->parent_mii_bus->read(p->parent_mii_bus,
+ phy_id + p->reg_offset,
+ regnum);
+}
+
+static int vsc848x_nexus_write(struct mii_bus *bus, int phy_id,
+ int regnum, u16 val)
+{
+ struct vsc848x_nexus_mdiobus *p = bus->priv;
+ return p->parent_mii_bus->write(p->parent_mii_bus,
+ phy_id + p->reg_offset,
+ regnum, val);
+}
+
+static int vsc848x_nexus_probe(struct platform_device *pdev)
+{
+ struct vsc848x_nexus_mdiobus *bus;
+ const char *bus_id;
+ int len;
+ int err = 0;
+
+ bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+ bus->parent_mii_bus = container_of(pdev->dev.parent,
+ struct mii_bus, dev);
+
+ /* The PHY nexux must have a reg property in the range [0-31] */
+ err = of_property_read_u32(pdev->dev.of_node, "reg", &bus->reg_offset);
+ if (err) {
+ dev_err(&pdev->dev, "%s has invalid PHY address\n",
+ pdev->dev.of_node->full_name);
+ return err;
+ }
+
+ bus->mii_bus = mdiobus_alloc();
+ if (!bus->mii_bus)
+ return -ENOMEM;
+
+ bus->mii_bus->priv = bus;
+ bus->mii_bus->irq = bus->phy_irq;
+ bus->mii_bus->name = "vsc848x_nexus";
+ bus_id = bus->parent_mii_bus->id;
+ len = strlen(bus_id);
+ if (len > MII_BUS_ID_SIZE - 4)
+ bus_id += len - (MII_BUS_ID_SIZE - 4);
+ snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s:%02x",
+ bus_id, bus->reg_offset);
+ bus->mii_bus->parent = &pdev->dev;
+
+ bus->mii_bus->read = vsc848x_nexus_read;
+ bus->mii_bus->write = vsc848x_nexus_write;
+ mutex_init(&bus->lock);
+
+ dev_set_drvdata(&pdev->dev, bus);
+
+ err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node);
+ if (err) {
+ dev_err(&pdev->dev, "Error registering with device tree\n");
+ goto fail_register;
+ }
+
+ return 0;
+
+fail_register:
+ dev_err(&pdev->dev, "Failed to register\n");
+ mdiobus_free(bus->mii_bus);
+ return err;
+}
+
+static int vsc848x_nexus_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id vsc848x_nexus_match[] = {
+ {
+ .compatible = "vitesse,vsc8488-nexus",
+ },
+ {
+ .compatible = "vitesse,vsc8486-nexus",
+ },
+ {
+ .compatible = "vitesse,vsc8484-nexus",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, vsc848x_nexus_match);
+
+static struct platform_driver vsc848x_nexus_driver = {
+ .driver = {
+ .name = "vsc848x-nexus",
+ .owner = THIS_MODULE,
+ .of_match_table = vsc848x_nexus_match,
+ },
+ .probe = vsc848x_nexus_probe,
+ .remove = vsc848x_nexus_remove,
+};
+
+static int __init vsc848x_mod_init(void)
+{
+ int rv;
+
+ rv = platform_driver_register(&vsc848x_nexus_driver);
+ if (rv)
+ return rv;
+
+ rv = phy_driver_register(&vsc848x_phy_driver);
+
+ return rv;
+}
+module_init(vsc848x_mod_init);
+
+static void __exit vsc848x_mod_exit(void)
+{
+ phy_driver_unregister(&vsc848x_phy_driver);
+ platform_driver_unregister(&vsc848x_nexus_driver);
+}
+module_exit(vsc848x_mod_exit);
+
+MODULE_DESCRIPTION("Driver for Vitesse VSC848X PHY");
+MODULE_AUTHOR("David Daney and Aaron Williams");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,310 @@
From: Abhishek Paliwal <abhishek.paliwal@aricent.com>
Date: Fri, 13 Feb 2015 12:47:36 +0530
Subject: of: Add of_memory_accessor to map device tree node to memory accessor
functions.
From: Aaron Williams <aaron.williams@cavium.com>
Currently there is no easy way to map a device tree node to a memory
accessor function for devices like I2C EEPROMs. For example, the Vitesse
vsc848x 10G PHY driver needs to be able to use the I2C at24 serial EEPROM
memory accessor function in order to read the SFP+ eeprom.
This provides a way where the vsc848x module can parse its device tree and
easily gain the accessor functions for the eeprom through a phandle.
This may be useful for any module which provides memory accessor functions.
Signed-off-by: Aaron Williams <aaron.williams@cavium.com>
Signed-off-by: Leonid Rosenboim <lrosenboim@caviumnetworks.com>
Signed-off-by: Abhishek Paliwal <abhishek.paliwal@aricent.com>
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -107,4 +107,10 @@
# arches should select this if DMA is coherent by default for OF devices
bool
+config OF_MEMORY_ACCESSOR
+ def_bool y
+ help
+ OpenFirmware memory accessor support for accessing devices like
+ i2c and SPI eeproms.
+
endif # OF
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -16,3 +16,4 @@
obj-$(CONFIG_OF_NUMA) += of_numa.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
+obj-$(CONFIG_OF_MEMORY_ACCESSOR) += of_memory_accessor.o
--- /dev/null
+++ b/drivers/of/of_memory_accessor.c
@@ -0,0 +1,192 @@
+/*
+ * Memory accessor OF helpers
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 Cavium Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_memory_accessor.h>
+#include <linux/list.h>
+#include <linux/memory.h>
+
+struct of_macc_entry {
+ struct list_head list;
+ struct device *dev;
+ struct memory_accessor *macc;
+ int ref;
+};
+
+static DEFINE_MUTEX(lock);
+static LIST_HEAD(macc_list);
+
+/**
+ * Adds a mapping of a device node to a memory accessor
+ *
+ * @param[in] dev - device
+ * @param[in] macc - memory accessor
+ *
+ * @returns 0 for success or -ENOMEM
+ */
+int of_memory_accessor_register(struct device *dev,
+ struct memory_accessor *macc)
+{
+ struct of_macc_entry *mentry;
+
+ mentry = kmalloc(sizeof(*mentry), GFP_KERNEL);
+ if (mentry == NULL)
+ return -ENOMEM;
+
+ mentry->dev = dev;
+ mentry->macc = macc;
+ mentry->ref = 0;
+
+ mutex_lock(&lock);
+
+ list_add(&(mentry->list), &macc_list);
+
+ mutex_unlock(&lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(of_memory_accessor_register);
+
+/**
+ * removes the mapping of a device node to a memory accessor
+ *
+ * @param[in] devnode - device node to remove
+ *
+ * @returns 0 for success or -ENODEV if device node not found, -EBUSY if still
+ * in use
+ */
+
+int of_memory_accessor_remove(struct device *dev)
+{
+ struct of_macc_entry *mentry;
+ struct list_head *pos, *q;
+ int ret = -ENODEV;
+
+ mutex_lock(&lock);
+
+ list_for_each_safe(pos, q, &macc_list) {
+ mentry = list_entry(pos, struct of_macc_entry, list);
+ if (mentry->dev == dev) {
+ if (mentry->ref > 0) {
+ ret = -EBUSY;
+ goto done;
+ }
+ list_del(pos);
+ kfree(mentry);
+ ret = 0;
+ goto done;
+ }
+ }
+
+ /* Not found */
+done:
+ mutex_unlock(&lock);
+ return ret;
+}
+EXPORT_SYMBOL(of_memory_accessor_remove);
+
+/**
+ * Returns the memory accessor for a device node and increments a reference
+ * count
+ *
+ * @param[in] devnode - device node to look up
+ *
+ * @returns memory accessor for device node or NULL if none found.
+ */
+struct memory_accessor *
+of_memory_accessor_get(const struct device_node *devnode)
+{
+ struct of_macc_entry *mentry;
+ struct list_head *pos;
+ struct memory_accessor *macc = NULL;
+
+ mutex_lock(&lock);
+
+ list_for_each(pos, &macc_list) {
+ mentry = list_entry(pos, struct of_macc_entry, list);
+ if (mentry->dev->of_node == devnode) {
+ macc = mentry->macc;
+ if (!mentry->ref) {
+ if (!try_module_get(mentry->dev->driver->owner)) {
+ macc = NULL;
+ pr_info("Warning: module for %s not found!",
+ mentry->dev->of_node->full_name);
+ }
+ }
+ mentry->ref++;
+ goto done;
+ }
+ }
+done:
+ mutex_unlock(&lock);
+ return macc;
+}
+EXPORT_SYMBOL(of_memory_accessor_get);
+
+/**
+ * Decrements the reference count for the memory accessor attached to the
+ * device node.
+ *
+ * @param[in] devnode - device node to look up
+ *
+ * @returns 0 for success or -ENODEV if the device node was not found.
+ */
+int of_memory_accessor_put(const struct device_node *devnode)
+{
+ struct of_macc_entry *mentry;
+ struct list_head *pos;
+ int ret = -ENODEV;
+
+ mutex_lock(&lock);
+ list_for_each(pos, &macc_list) {
+ mentry = list_entry(pos, struct of_macc_entry, list);
+ if (mentry->dev->of_node == devnode) {
+ if (mentry->ref > 0)
+ mentry->ref--;
+ if (!mentry->ref)
+ module_put(mentry->dev->driver->owner);
+
+ module_put(THIS_MODULE);
+ ret = 0;
+ goto done;
+ }
+ }
+done:
+ mutex_unlock(&lock);
+ return ret;
+}
+EXPORT_SYMBOL(of_memory_accessor_put);
+
+static void __exit of_memory_accessor_exit(void)
+{
+ struct of_macc_entry *mentry;
+ struct list_head *pos, *q;
+
+ list_for_each_safe(pos, q, &macc_list) {
+ mentry = list_entry(pos, struct of_macc_entry, list);
+ if (mentry->ref)
+ module_put(mentry->dev->driver->owner);
+ list_del(pos);
+ kfree(mentry);
+ }
+
+ /* Not found */
+ mutex_destroy(&lock);
+ list_del(&macc_list);
+}
+module_exit(of_memory_accessor_exit);
+
+MODULE_DESCRIPTION("Driver for mapping device nodes to memory accessors");
+MODULE_AUTHOR("Aaron Williams");
+MODULE_LICENSE("GPL");
--- /dev/null
+++ b/include/linux/of_memory_accessor.h
@@ -0,0 +1,71 @@
+#ifndef _LINUX_OF_MEMORY_ACCESSOR_H
+#define _LINUX_OF_MEMORY_ACCESSOR_H
+/*
+ * Memory accessor OF helpers
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 Cavium Inc.
+ */
+
+#include <linux/of.h>
+#include <linux/memory.h>
+
+/**
+ * Adds a mapping of a device node to a memory accessor
+ *
+ * @param[in] dev - device
+ * @param[in] macc - memory accessor
+ *
+ * @returns 0 for success or -ENOMEM
+ */
+#ifdef CONFIG_OF_MEMORY_ACCESSOR
+int of_memory_accessor_register(struct device *dev,
+ struct memory_accessor *macc);
+#else
+static inline int of_memory_accessor_register(struct device *dev,
+ struct memory_accessor *macc)
+{
+ return 0;
+}
+#endif
+
+/**
+ * removes the mapping of a device node to a memory accessor
+ *
+ * @param[in] devnode - device node to remove
+ *
+ * @returns 0 for success or 1 if device node not found
+ */
+#ifdef CONFIG_OF_MEMORY_ACCESSOR
+int of_memory_accessor_remove(struct device *dev);
+#else
+static inline int of_memory_accessor_remove(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+/**
+ * Returns the memory accessor for a device node
+ *
+ * @param[in] devnode - device node to look up
+ *
+ * @returns memory accessor for device node or NULL if none found.
+ */
+struct memory_accessor *
+of_memory_accessor_get(const struct device_node *devnode);
+
+/**
+ * Decrements the reference count for the memory accessor attached to the
+ * device node.
+ *
+ * @param[in] devnode - device node to look up
+ *
+ * @returns 0 for success or -1 if the device node was not found.
+ */
+int of_memory_accessor_put(const struct device_node *devnode);
+
+#endif /* _LINUX_OF_MEMORY_ACCESSOR_H */

View File

@ -0,0 +1,42 @@
From: Abhishek Paliwal <abhishek.paliwal@aricent.com>
Date: Fri, 13 Feb 2015 12:48:16 +0530
Subject: misc/at24: Register memory accessor functions with of_memory_accessor
From: Aaron Williams <aaron.williams@cavium.com>
The at24 module will now register its memory accessor functions with its
device tree entry so that other modules may call these functions based on
the device tree node.
Signed-off-by: Aaron Williams <aaron.williams@cavium.com>
Signed-off-by: Leonid Rosenboim <lrosenboim@caviumnetworks.com>
Signed-off-by: Abhishek Paliwal <abhishek.paliwal@aricent.com>
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -23,6 +23,7 @@
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <linux/gpio/consumer.h>
+#include <linux/of_memory_accessor.h>
/* Address pointer is 16 bit. */
#define AT24_FLAG_ADDR16 BIT(7)
@@ -720,6 +721,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
byte_len, client->name,
writable ? "writable" : "read-only", at24->write_max);
+ if (client->dev.of_node)
+ of_memory_accessor_register(&client->dev, &at24->macc);
+
return 0;
}
@@ -728,5 +732,8 @@ static int at24_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
+ if (client->dev.of_node)
+ of_memory_accessor_remove(&client->dev);
+
return 0;
}

View File

@ -0,0 +1,18 @@
--- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h
+++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h
@@ -253,6 +253,7 @@ enum cvmx_board_types_enum {
CVMX_BOARD_TYPE_REDWING = 43,
CVMX_BOARD_TYPE_NIC68_4 = 44,
CVMX_BOARD_TYPE_NIC10E_66 = 45,
+ CVMX_BOARD_TYPE_SNIC10E = 50,
CVMX_BOARD_TYPE_MAX,
/*
@@ -366,6 +367,7 @@ static inline const char *cvmx_board_type_to_string(enum
ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_REDWING)
ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC68_4)
ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E_66)
+ ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_SNIC10E)
ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX)
/* Customer boards listed here */

View File

@ -0,0 +1,79 @@
--- a/arch/mips/cavium-octeon/executive/cvmx-helper.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c
@@ -1041,12 +1041,14 @@ int cvmx_helper_initialize_packet_io_global(void)
result |= __cvmx_helper_interface_setup_ipd(interface);
result |= __cvmx_helper_interface_setup_pko(interface);
}
-
+ cvmx_dprintf("Gets past end of interfaces setup\n");
result |= __cvmx_helper_global_setup_ipd();
result |= __cvmx_helper_global_setup_pko();
+ cvmx_dprintf("Sets up global helpers\n");
/* Enable any flow control and backpressure */
result |= __cvmx_helper_global_setup_backpressure();
+ cvmx_dprintf("Sets up backpressure helpers\n");
#if CVMX_HELPER_ENABLE_IPD
result |= cvmx_helper_ipd_and_packet_input_enable();
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -700,6 +700,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
cvm_oct_configure_common_hw();
cvmx_helper_initialize_packet_io_global();
+ pr_err("OK, we got out of packet_io_global()\n");
if (receive_group_order) {
if (receive_group_order > 4)
@@ -709,9 +710,11 @@ static int cvm_oct_probe(struct platform_device *pdev)
pow_receive_groups = BIT(pow_receive_group);
}
+ pr_err("We got through receive_group_order\n");
/* Change the input group for all ports before input is enabled */
num_interfaces = cvmx_helper_get_number_of_interfaces();
for (interface = 0; interface < num_interfaces; interface++) {
+ pr_err("We are starting on interface %d\n", interface);
int num_ports = cvmx_helper_ports_on_interface(interface);
int port;
@@ -752,14 +755,14 @@ static int cvm_oct_probe(struct platform_device *pdev)
pip_prt_tagx.s.grptag = 0;
pip_prt_tagx.s.grp = pow_receive_group;
}
-
+ pr_err("COULD IT BE CSR WRITES???\n");
cvmx_write_csr(CVMX_PIP_PRT_TAGX(port),
pip_prt_tagx.u64);
}
}
-
+ pr_err("COULD it be cvmx_helper_ipd_and_packet_input_enable???\n");
cvmx_helper_ipd_and_packet_input_enable();
-
+ pr_err("COULD it be this memset??\n");
memset(cvm_oct_device, 0, sizeof(cvm_oct_device));
/*
@@ -804,6 +807,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
}
}
+ pr_err("OK, we got THIS far, all the way to the interface init. Which is weird, we shoulda crashed by now\n");
num_interfaces = cvmx_helper_get_number_of_interfaces();
for (interface = 0; interface < num_interfaces; interface++) {
cvmx_helper_interface_mode_t imode =
@@ -860,8 +864,10 @@ static int cvm_oct_probe(struct platform_device *pdev)
break;
case CVMX_HELPER_INTERFACE_MODE_XAUI:
- dev->netdev_ops = &cvm_oct_xaui_netdev_ops;
- strscpy(dev->name, "xaui%d", sizeof(dev->name));
+ if (of_device_is_available(priv->of_node)) {
+ dev->netdev_ops = &cvm_oct_xaui_netdev_ops;
+ strscpy(dev->name, "xaui%d", sizeof(dev->name));
+ }
break;
case CVMX_HELPER_INTERFACE_MODE_LOOP:

View File

@ -0,0 +1,48 @@
--- a/arch/mips/cavium-octeon/executive/cvmx-helper.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c
@@ -971,6 +971,7 @@ int cvmx_helper_ipd_and_packet_input_enable(void)
int interface;
/* Enable IPD */
+ cvmx_dprintf("COULD IT BE cvmx_ipd_enable???\n");
cvmx_ipd_enable();
/*
@@ -978,13 +979,16 @@ int cvmx_helper_ipd_and_packet_input_enable(void)
* that at this point IPD/PIP must be fully functional and PKO
* must be disabled
*/
+ cvmx_dprintf("COULD IT BE getting no of interfaces????\n");
num_interfaces = cvmx_helper_get_number_of_interfaces();
for (interface = 0; interface < num_interfaces; interface++) {
+ cvmx_dprintf("COULD IT BE interface # %d ??ces????\n", interface);
if (cvmx_helper_ports_on_interface(interface) > 0)
__cvmx_helper_packet_hardware_enable(interface);
}
/* Finally enable PKO now that the entire path is up and running */
+ cvmx_dprintf("COULD IT BE PKO???\n");
cvmx_pko_enable();
if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1)
--- a/arch/mips/include/asm/octeon/cvmx-ipd.h
+++ b/arch/mips/include/asm/octeon/cvmx-ipd.h
@@ -129,15 +129,18 @@ static inline void cvmx_ipd_config(uint64_t mbuff_size,
static inline void cvmx_ipd_enable(void)
{
union cvmx_ipd_ctl_status ipd_reg;
+ cvmx_dprintf("COULD IT BE THIS ONE CSR READ IN cvmx_ipd_enable ??\n");
ipd_reg.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS);
if (ipd_reg.s.ipd_en) {
cvmx_dprintf
("Warning: Enabling IPD when IPD already enabled.\n");
}
+ cvmx_dprintf("OK IT PASSED THE READ. BUT THERE'S THIS CVMX_ENABLE_LEN_M8_FIX THAT COULD APPLY??\n");
ipd_reg.s.ipd_en = 1;
#if CVMX_ENABLE_LEN_M8_FIX
if (!OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2))
ipd_reg.s.len_m8 = TRUE;
#endif
+ cvmx_dprintf("COULD IT BE THIS ONE CSR WRITE??? IN cvmx_ipd_enable ??\n");
cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_reg.u64);
}

View File

@ -0,0 +1,186 @@
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
index 93a498d05184..27733d710355 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
@@ -121,58 +121,80 @@ int __cvmx_helper_xaui_enable(int interface)
union cvmx_gmxx_tx_int_en gmx_tx_int_en;
union cvmx_pcsxx_int_en_reg pcsx_int_en_reg;
+ cvmx_dprintf("COULD IT BE THE FEATURE CHECK FOR PKND??\n");
/* Setup PKND */
if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
+ cvmx_dprintf("COULD IT BE THE FIRST CSR READ??\n");
gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
+ cvmx_dprintf("COULD IT BE THE second CSR READ??\n");
gmx_cfg.s.pknd = cvmx_helper_get_ipd_port(interface, 0);
+ cvmx_dprintf("COULD IT BE THE third CSR /write READ??\n");
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
}
/* (1) Interface has already been enabled. */
/* (2) Disable GMX. */
+ cvmx_dprintf("step2 start!?? could it be the csr read??\n");
xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
xauiMiscCtl.s.gmxeno = 1;
+ cvmx_dprintf("step2 could it be the csr write to disable gmx??\n");
cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
/* (3) Disable GMX and PCSX interrupts. */
+ cvmx_dprintf("step3 start. could it be the csr read??\n");
gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0, interface));
+ cvmx_dprintf("step3 start. could it be the write for disabling interrupts???\n");
cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0);
+ cvmx_dprintf("step3 start. could it be read for setting up the gmx_tx_int_en???\n");
gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface));
+ cvmx_dprintf("step3 start. could it be the cvmx_gmxx write???\n");
cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
+ cvmx_dprintf("step3 start almost done. show up tell us about the PCSXX write???\n");
pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface));
+ cvmx_dprintf("step3, this final csr write?\n");
cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
/* (4) Bring up the PCSX and GMX reconciliation layer. */
/* (4)a Set polarity and lane swapping. */
/* (4)b */
+ cvmx_dprintf("4.1\n");
gmxXauiTxCtl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
/* Enable better IFG packing and improves performance */
gmxXauiTxCtl.s.dic_en = 1;
gmxXauiTxCtl.s.uni_en = 0;
+ cvmx_dprintf("4.2\n");
cvmx_write_csr(CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64);
/* (4)c Aply reset sequence */
+ cvmx_dprintf("4.3\n");
xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
xauiCtl.s.lo_pwr = 0;
/* Issuing a reset here seems to hang some CN68XX chips. */
if (!OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X) &&
- !OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X))
+ !OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X) &&
+ 0)
xauiCtl.s.reset = 1;
+ cvmx_dprintf("4.4\n");
cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64);
+ cvmx_dprintf("4.5\n");
/* Wait for PCS to come out of reset */
if (CVMX_WAIT_FOR_FIELD64
(CVMX_PCSXX_CONTROL1_REG(interface), union cvmx_pcsxx_control1_reg,
reset, ==, 0, 10000))
return -1;
+
+ cvmx_dprintf("4.6\n");
/* Wait for PCS to be aligned */
if (CVMX_WAIT_FOR_FIELD64
(CVMX_PCSXX_10GBX_STATUS_REG(interface),
union cvmx_pcsxx_10gbx_status_reg, alignd, ==, 1, 10000))
return -1;
+
+ cvmx_dprintf("4.7\n");
/* Wait for RX to be ready */
if (CVMX_WAIT_FOR_FIELD64
(CVMX_GMXX_RX_XAUI_CTL(interface), union cvmx_gmxx_rx_xaui_ctl,
@@ -180,8 +202,11 @@ int __cvmx_helper_xaui_enable(int interface)
return -1;
/* (6) Configure GMX */
+ cvmx_dprintf("6.1\n");
gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
+
gmx_cfg.s.en = 0;
+ cvmx_dprintf("6.2\n");
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
/* Wait for GMX RX to be idle */
@@ -189,62 +214,87 @@ int __cvmx_helper_xaui_enable(int interface)
(CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
rx_idle, ==, 1, 10000))
return -1;
+ cvmx_dprintf("6.3\n");
/* Wait for GMX TX to be idle */
if (CVMX_WAIT_FOR_FIELD64
(CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
tx_idle, ==, 1, 10000))
return -1;
+ cvmx_dprintf("6.4\n");
/* GMX configure */
gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
gmx_cfg.s.speed = 1;
gmx_cfg.s.speed_msb = 0;
gmx_cfg.s.slottime = 1;
+ cvmx_dprintf("6.5\n");
cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1);
+ cvmx_dprintf("6.6\n");
cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512);
+ cvmx_dprintf("6.7\n");
cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192);
+ cvmx_dprintf("6.8\n");
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
/* (7) Clear out any error state */
+ cvmx_dprintf("7.1\n");
cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0, interface),
cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0, interface)));
+ cvmx_dprintf("7.2\n");
cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface),
cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface)));
+ cvmx_dprintf("7.3\n");
cvmx_write_csr(CVMX_PCSXX_INT_REG(interface),
cvmx_read_csr(CVMX_PCSXX_INT_REG(interface)));
+ cvmx_dprintf("7.4\n");
/* Wait for receive link */
if (CVMX_WAIT_FOR_FIELD64
(CVMX_PCSXX_STATUS1_REG(interface), union cvmx_pcsxx_status1_reg,
rcv_lnk, ==, 1, 10000))
return -1;
+ cvmx_dprintf("7.5\n");
if (CVMX_WAIT_FOR_FIELD64
(CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
xmtflt, ==, 0, 10000))
return -1;
+ cvmx_dprintf("7.6\n");
if (CVMX_WAIT_FOR_FIELD64
(CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
rcvflt, ==, 0, 10000))
return -1;
+ cvmx_dprintf("7.7\n");
cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), gmx_rx_int_en.u64);
+ cvmx_dprintf("7.8\n");
cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64);
+ cvmx_dprintf("7.9\n");
cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64);
/* (8) Enable packet reception */
xauiMiscCtl.s.gmxeno = 0;
+ cvmx_dprintf("8.1\n");
cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
+ cvmx_dprintf("8.2\n");
gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
gmx_cfg.s.en = 1;
+ cvmx_dprintf("8.3\n");
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
+ cvmx_dprintf("8.4\n");
__cvmx_interrupt_pcsx_intx_en_reg_enable(0, interface);
+ cvmx_dprintf("8.5\n");
__cvmx_interrupt_pcsx_intx_en_reg_enable(1, interface);
+ cvmx_dprintf("8.6\n");
__cvmx_interrupt_pcsx_intx_en_reg_enable(2, interface);
+ cvmx_dprintf("8.7\n");
__cvmx_interrupt_pcsx_intx_en_reg_enable(3, interface);
+ cvmx_dprintf("8.8\n");
__cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
+ cvmx_dprintf("8.9\n");
__cvmx_interrupt_gmxx_enable(interface);
+ cvmx_dprintf("8.10\n");
return 0;
}