- MIPS: mscc: jr2: small fixes

- MIPS: mscc: luton: add ethernet and switch driver
 - MIPS: mt76xx: fix timer frequency
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEiQkHUH+J02LLC9InKPlOlyTyXBgFAlxURx8ACgkQKPlOlyTy
 XBjZWg//eo8rdWidwogApEUcwHqr6jGHrm5RwAaqJpNqLX5sLunNbNtzzNFvNL2o
 quU+8zjnUBgxWnPo/Aasx8cYh7nzW2cahyqsrUXeKjJmGualWMSR93iFmtIBXdmR
 WJg6erbJw6N9LUNA50/SPfSR6DqayvgQnt8kB/GKg5ASpZEfc2o7zzd0HFS3dFY2
 WU4irUY2INbjP3k9Qa+PIm8rOq52z/OqfQ3tX6SuoC1LOaYQJsyrYDmzxmqP4HV2
 JarsOqy1d8II3hsvTKJIypBeyRiln7rtSz0nPyQcUG4VRw9AOtMfnTY93gr0Ruzt
 UMVNnhJr78NzHly7ukqqmFBsQMq+gXbDDq6GbjPEfGcvy7AiprJYjokJ28JwraOi
 yfnwonJQU/k0E5PBX9f4AtkbDOedd/RWPRfQaUmTdGzxoCX/YvrOAe+yqWTov8To
 y5mnhx9QwIC8cxHgjaS7+xAXkcumA4xwG3g7wGntUqMuPmIiJObtZT4umEpLjW4d
 zL5wVmdRIALcTdfHS97T1QpDuJcVjFre98bfRGweXurX/ngQIEbh4e82JojW2CDN
 jAw/tVHkXcKBPoGE/hHEx0K4ScxjdswCXMeqKWjqHotvF+V6Mwnq8frecjgVEUGM
 E/bfSlzAVllfuug7wWccq69pvyQkn7YHg8HDuNwy3gdBCxZFY8c=
 =qCAc
 -----END PGP SIGNATURE-----

Merge tag 'mips-pull-2019-02-01' of git://git.denx.de/u-boot-mips

- MIPS: mscc: jr2: small fixes
- MIPS: mscc: luton: add ethernet and switch driver
- MIPS: mt76xx: fix timer frequency
This commit is contained in:
Tom Rini 2019-02-02 10:11:12 -05:00
commit 544d5e98f3
21 changed files with 1410 additions and 282 deletions

View File

@ -561,7 +561,7 @@ F: drivers/gpio/mscc_sgpio.c
F: drivers/spi/mscc_bb_spi.c F: drivers/spi/mscc_bb_spi.c
F: include/configs/vcoreiii.h F: include/configs/vcoreiii.h
F: drivers/pinctrl/mscc/ F: drivers/pinctrl/mscc/
F: drivers/net/ocelot_switch.c F: drivers/net/mscc_eswitch/
MIPS JZ4780 MIPS JZ4780
M: Ezequiel Garcia <ezequiel@collabora.com> M: Ezequiel Garcia <ezequiel@collabora.com>

View File

@ -55,3 +55,54 @@
}; };
}; };
&mdio0 {
status = "okay";
};
&port0 {
phy-handle = <&phy0>;
};
&port1 {
phy-handle = <&phy1>;
};
&port2 {
phy-handle = <&phy2>;
};
&port3 {
phy-handle = <&phy3>;
};
&port4 {
phy-handle = <&phy4>;
};
&port5 {
phy-handle = <&phy5>;
};
&port6 {
phy-handle = <&phy6>;
};
&port7 {
phy-handle = <&phy7>;
};
&port8 {
phy-handle = <&phy8>;
};
&port9 {
phy-handle = <&phy9>;
};
&port10 {
phy-handle = <&phy10>;
};
&port11 {
phy-handle = <&phy11>;
};

View File

@ -61,3 +61,54 @@
}; };
}; };
&mdio0 {
status = "okay";
};
&port0 {
phy-handle = <&phy0>;
};
&port1 {
phy-handle = <&phy1>;
};
&port2 {
phy-handle = <&phy2>;
};
&port3 {
phy-handle = <&phy3>;
};
&port4 {
phy-handle = <&phy4>;
};
&port5 {
phy-handle = <&phy5>;
};
&port6 {
phy-handle = <&phy6>;
};
&port7 {
phy-handle = <&phy7>;
};
&port8 {
phy-handle = <&phy8>;
};
&port9 {
phy-handle = <&phy9>;
};
&port10 {
phy-handle = <&phy10>;
};
&port11 {
phy-handle = <&phy11>;
};

View File

@ -92,5 +92,170 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
}; };
switch: switch@1010000 {
compatible = "mscc,vsc7527-switch";
reg = <0x1e0000 0x0100>, // VTSS_TO_DEV_0
<0x1f0000 0x0100>, // VTSS_TO_DEV_1
<0x200000 0x0100>, // VTSS_TO_DEV_2
<0x210000 0x0100>, // VTSS_TO_DEV_3
<0x220000 0x0100>, // VTSS_TO_DEV_4
<0x230000 0x0100>, // VTSS_TO_DEV_5
<0x240000 0x0100>, // VTSS_TO_DEV_6
<0x250000 0x0100>, // VTSS_TO_DEV_7
<0x260000 0x0100>, // VTSS_TO_DEV_8
<0x270000 0x0100>, // VTSS_TO_DEV_9
<0x280000 0x0100>, // VTSS_TO_DEV_10
<0x290000 0x0100>, // VTSS_TO_DEV_11
<0x2a0000 0x0100>, // VTSS_TO_DEV_12
<0x2b0000 0x0100>, // VTSS_TO_DEV_13
<0x2c0000 0x0100>, // VTSS_TO_DEV_14
<0x2d0000 0x0100>, // VTSS_TO_DEV_15
<0x2e0000 0x0100>, // VTSS_TO_DEV_16
<0x2f0000 0x0100>, // VTSS_TO_DEV_17
<0x300000 0x0100>, // VTSS_TO_DEV_18
<0x310000 0x0100>, // VTSS_TO_DEV_19
<0x320000 0x0100>, // VTSS_TO_DEV_20
<0x330000 0x0100>, // VTSS_TO_DEV_21
<0x340000 0x0100>, // VTSS_TO_DEV_22
<0x350000 0x0100>, // VTSS_TO_DEV_23
<0x010000 0x1000>, // VTSS_TO_SYS
<0x020000 0x1000>, // VTSS_TO_ANA
<0x030000 0x1000>, // VTSS_TO_REW
<0x070000 0x1000>, // VTSS_TO_DEVCPU_GCB
<0x080000 0x0100>, // VTSS_TO_DEVCPU_QS
<0x0a0000 0x0100>; // VTSS_TO_HSIO
reg-names = "port0", "port1", "port2", "port3",
"port4", "port5", "port6", "port7",
"port8", "port9", "port10", "port11",
"port12", "port13", "port14", "port15",
"port16", "port17", "port18", "port19",
"port20", "port21", "port22", "port23",
"sys", "ana", "rew", "gcb", "qs", "hsio";
status = "okay";
ethernet-ports {
#address-cells = <1>;
#size-cells = <0>;
port0: port@0 {
reg = <0>;
};
port1: port@1 {
reg = <1>;
};
port2: port@2 {
reg = <2>;
};
port3: port@3 {
reg = <3>;
};
port4: port@4 {
reg = <4>;
};
port5: port@5 {
reg = <5>;
};
port6: port@6 {
reg = <6>;
};
port7: port@7 {
reg = <7>;
};
port8: port@8 {
reg = <8>;
};
port9: port@9 {
reg = <9>;
};
port10: port@10 {
reg = <10>;
};
port11: port@11 {
reg = <11>;
};
port12: port@12 {
reg = <12>;
};
port13: port@13 {
reg = <13>;
};
port14: port@14 {
reg = <14>;
};
port15: port@15 {
reg = <15>;
};
port16: port@16 {
reg = <16>;
};
port17: port@17 {
reg = <17>;
};
port18: port@18 {
reg = <18>;
};
port19: port@19 {
reg = <19>;
};
port20: port@20 {
reg = <20>;
};
port21: port@21 {
reg = <21>;
};
port22: port@22 {
reg = <22>;
};
port23: port@23 {
reg = <23>;
};
};
};
mdio0: mdio@700a0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "mscc,luton-miim";
reg = <0x700a0 0x24>;
status = "disabled";
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
phy2: ethernet-phy@2 {
reg = <2>;
};
phy3: ethernet-phy@3 {
reg = <3>;
};
phy4: ethernet-phy@4 {
reg = <4>;
};
phy5: ethernet-phy@5 {
reg = <5>;
};
phy6: ethernet-phy@6 {
reg = <6>;
};
phy7: ethernet-phy@7 {
reg = <7>;
};
phy8: ethernet-phy@8 {
reg = <8>;
};
phy9: ethernet-phy@9 {
reg = <9>;
};
phy10: ethernet-phy@10 {
reg = <10>;
};
phy11: ethernet-phy@11 {
reg = <11>;
};
};
}; };
}; };

View File

@ -64,6 +64,13 @@ static void vcoreiii_gpio_set_alternate(int gpio, int mode)
} }
} }
void board_debug_uart_init(void)
{
/* too early for the pinctrl driver, so configure the UART pins here */
vcoreiii_gpio_set_alternate(10, 1);
vcoreiii_gpio_set_alternate(11, 1);
}
static void do_board_detect(void) static void do_board_detect(void)
{ {
int i; int i;
@ -73,6 +80,9 @@ static void do_board_detect(void)
for (i = 56; i < 60; i++) for (i = 56; i < 60; i++)
vcoreiii_gpio_set_alternate(i, 1); vcoreiii_gpio_set_alternate(i, 1);
/* small delay for settling the pins */
mdelay(30);
if (mscc_phy_rd(0, 0x10, 0x3, &pval) == 0 && if (mscc_phy_rd(0, 0x10, 0x3, &pval) == 0 &&
((pval >> 4) & 0x3F) == 0x3c) { ((pval >> 4) & 0x3F) == 0x3c) {
gd->board_type = BOARD_TYPE_PCB112; /* Serval2-NID */ gd->board_type = BOARD_TYPE_PCB112; /* Serval2-NID */

View File

@ -56,3 +56,9 @@ CONFIG_SYS_NS16550=y
CONFIG_SPI=y CONFIG_SPI=y
CONFIG_DM_SPI=y CONFIG_DM_SPI=y
CONFIG_LZMA=y CONFIG_LZMA=y
CONFIG_DEBUG_UART_BOARD_INIT=y
CONFIG_DEBUG_UART_BASE=0x70100000
CONFIG_DEBUG_UART_CLOCK=250000000
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_SHIFT=2
CONFIG_DEBUG_UART_ANNOUNCE=y

View File

@ -60,6 +60,7 @@ CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_WINBOND=y CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SPI_FLASH_MTD=y CONFIG_SPI_FLASH_MTD=y
CONFIG_DM_ETH=y CONFIG_DM_ETH=y
CONFIG_MSCC_LUTON_SWITCH=y
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
CONFIG_DM_SERIAL=y CONFIG_DM_SERIAL=y

View File

@ -432,12 +432,7 @@ config SNI_AVE
This driver implements support for the Socionext AVE Ethernet This driver implements support for the Socionext AVE Ethernet
controller, as found on the Socionext UniPhier family. controller, as found on the Socionext UniPhier family.
config MSCC_OCELOT_SWITCH source "drivers/net/mscc_eswitch/Kconfig"
bool "Ocelot switch driver"
depends on DM_ETH && ARCH_MSCC
select PHYLIB
help
This driver supports the Ocelot network switch device.
config ETHER_ON_FEC1 config ETHER_ON_FEC1
bool "FEC1" bool "FEC1"

View File

@ -75,4 +75,4 @@ obj-$(CONFIG_FSL_PFE) += pfe_eth/
obj-$(CONFIG_SNI_AVE) += sni_ave.o obj-$(CONFIG_SNI_AVE) += sni_ave.o
obj-y += ti/ obj-y += ti/
obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o obj-y += mscc_eswitch/

View File

@ -0,0 +1,17 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2019 Microsemi Corporation
config MSCC_OCELOT_SWITCH
bool "Ocelot switch driver"
depends on DM_ETH && ARCH_MSCC
select PHYLIB
help
This driver supports the Ocelot network switch device.
config MSCC_LUTON_SWITCH
bool "Luton switch driver"
depends on DM_ETH && ARCH_MSCC
select PHYLIB
help
This driver supports the Luton network switch device.

View File

@ -0,0 +1,3 @@
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o
obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o

View File

@ -0,0 +1,736 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Microsemi Corporation
*/
#include <common.h>
#include <config.h>
#include <dm.h>
#include <dm/of_access.h>
#include <dm/of_addr.h>
#include <fdt_support.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <miiphy.h>
#include <net.h>
#include <wait_bit.h>
#include "mscc_miim.h"
#include "mscc_xfer.h"
#include "mscc_mac_table.h"
#define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x))
#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
#define ANA_PORT_CPU_FWD_CFG(x) (0x50 + 0x80 * (x))
#define ANA_PORT_CPU_FWD_CFG_SRC_COPY_ENA BIT(1)
#define ANA_PORT_PORT_CFG(x) (0x60 + 0x80 * (x))
#define ANA_PORT_PORT_CFG_RECV_ENA BIT(5)
#define ANA_PGID(x) (0x1000 + 4 * (x))
#define SYS_FRM_AGING 0x8300
#define SYS_SYSTEM_RST_CFG 0x81b0
#define SYS_SYSTEM_RST_MEM_INIT BIT(0)
#define SYS_SYSTEM_RST_MEM_ENA BIT(1)
#define SYS_SYSTEM_RST_CORE_ENA BIT(2)
#define SYS_PORT_MODE(x) (0x81bc + 0x4 * (x))
#define SYS_PORT_MODE_INCL_INJ_HDR BIT(0)
#define SYS_SWITCH_PORT_MODE(x) (0x8294 + 0x4 * (x))
#define SYS_SWITCH_PORT_MODE_PORT_ENA BIT(3)
#define SYS_EGR_NO_SHARING 0x8378
#define SYS_SCH_CPU 0x85a0
#define REW_PORT_CFG(x) (0x8 + 0x80 * (x))
#define REW_PORT_CFG_IFH_INSERT_ENA BIT(7)
#define GCB_DEVCPU_RST_SOFT_CHIP_RST 0x90
#define GCB_DEVCPU_RST_SOFT_CHIP_RST_SOFT_PHY BIT(1)
#define GCB_MISC_STAT 0x11c
#define GCB_MISC_STAT_PHY_READY BIT(3)
#define QS_XTR_MAP(x) (0x10 + 4 * (x))
#define QS_XTR_MAP_GRP BIT(4)
#define QS_XTR_MAP_ENA BIT(0)
#define HSIO_PLL5G_CFG_PLL5G_CFG2 0x8
#define HSIO_RCOMP_CFG_CFG0 0x20
#define HSIO_RCOMP_CFG_CFG0_MODE_SEL(x) ((x) << 8)
#define HSIO_RCOMP_CFG_CFG0_RUN_CAL BIT(12)
#define HSIO_RCOMP_STATUS 0x24
#define HSIO_RCOMP_STATUS_BUSY BIT(12)
#define HSIO_RCOMP_STATUS_RCOMP_M GENMASK(3, 0)
#define HSIO_SERDES6G_ANA_CFG_DES_CFG 0x64
#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(x) ((x) << 1)
#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(x) ((x) << 5)
#define HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(x) ((x) << 10)
#define HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(x) ((x) << 13)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG 0x68
#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(x) (x)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(x) ((x) << 4)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(x) ((x) << 7)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(x) ((x) << 9)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(x) ((x) << 14)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG1 0x6c
#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST BIT(0)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC BIT(2)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC BIT(3)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE BIT(6)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF BIT(7)
#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(x) ((x) << 8)
#define HSIO_SERDES6G_ANA_CFG_OB_CFG 0x70
#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(x) ((x) << 4)
#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H BIT(8)
#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(x) ((x) << 23)
#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POL BIT(29)
#define HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE BIT(30)
#define HSIO_SERDES6G_ANA_CFG_OB_CFG1 0x74
#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(x) (x)
#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(x) ((x) << 6)
#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG 0x7c
#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(x) (x)
#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE BIT(18)
#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST BIT(31)
#define HSIO_SERDES6G_ANA_CFG_PLL_CFG 0x80
#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA BIT(7)
#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
#define HSIO_SERDES6G_ANA_CFG_SER_CFG 0x84
#define HSIO_SERDES6G_DIG_CFG_MISC_CFG 0x88
#define HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST BIT(0)
#define HSIO_MCB_SERDES6G_CFG 0xac
#define HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT BIT(31)
#define HSIO_MCB_SERDES6G_CFG_ADDR(x) (x)
#define DEV_GMII_PORT_MODE_CLK 0x0
#define DEV_GMII_PORT_MODE_CLK_PHY_RST BIT(0)
#define DEV_GMII_MAC_CFG_MAC_ENA 0xc
#define DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
#define DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
#define DEV_PORT_MODE_CLK 0x4
#define DEV_PORT_MODE_CLK_PHY_RST BIT(2)
#define DEV_PORT_MODE_CLK_LINK_SPEED_1000 1
#define DEV_MAC_CFG_MAC_ENA 0x10
#define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
#define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
#define DEV_MAC_CFG_MAC_IFG 0x24
#define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8)
#define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4)
#define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x)
#define DEV_PCS1G_CFG_PCS1G_CFG 0x40
#define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0)
#define DEV_PCS1G_CFG_PCS1G_MODE 0x44
#define DEV_PCS1G_CFG_PCS1G_SD 0x48
#define DEV_PCS1G_CFG_PCS1G_ANEG 0x4c
#define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
#define IFH_INJ_BYPASS BIT(31)
#define IFH_TAG_TYPE_C 0
#define MAC_VID 1
#define CPU_PORT 26
#define INTERNAL_PORT_MSK 0xFFFFFF
#define IFH_LEN 2
#define ETH_ALEN 6
#define PGID_BROADCAST 28
#define PGID_UNICAST 29
#define PGID_SRC 80
enum luton_target {
PORT0,
PORT1,
PORT2,
PORT3,
PORT4,
PORT5,
PORT6,
PORT7,
PORT8,
PORT9,
PORT10,
PORT11,
PORT12,
PORT13,
PORT14,
PORT15,
PORT16,
PORT17,
PORT18,
PORT19,
PORT20,
PORT21,
PORT22,
PORT23,
SYS,
ANA,
REW,
GCB,
QS,
HSIO,
TARGET_MAX,
};
#define MAX_PORT (PORT23 - PORT0 + 1)
#define MIN_INT_PORT PORT0
#define MAX_INT_PORT (PORT11 - PORT0 + 1)
#define MIN_EXT_PORT PORT12
#define MAX_EXT_PORT MAX_PORT
enum luton_mdio_target {
MIIM,
TARGET_MDIO_MAX,
};
enum luton_phy_id {
INTERNAL,
EXTERNAL,
NUM_PHY,
};
struct luton_private {
void __iomem *regs[TARGET_MAX];
struct mii_dev *bus[NUM_PHY];
};
static const unsigned long luton_regs_qs[] = {
[MSCC_QS_XTR_RD] = 0x18,
[MSCC_QS_XTR_FLUSH] = 0x28,
[MSCC_QS_XTR_DATA_PRESENT] = 0x2c,
[MSCC_QS_INJ_WR] = 0x3c,
[MSCC_QS_INJ_CTRL] = 0x44,
};
static const unsigned long luton_regs_ana_table[] = {
[MSCC_ANA_TABLES_MACHDATA] = 0x11b0,
[MSCC_ANA_TABLES_MACLDATA] = 0x11b4,
[MSCC_ANA_TABLES_MACACCESS] = 0x11b8,
};
static struct mscc_miim_dev miim[NUM_PHY];
static struct mii_dev *luton_mdiobus_init(struct udevice *dev,
int mdiobus_id)
{
unsigned long phy_size[NUM_PHY];
phys_addr_t phy_base[NUM_PHY];
struct ofnode_phandle_args phandle;
ofnode eth_node, node, mdio_node;
struct resource res;
struct mii_dev *bus;
fdt32_t faddr;
int i;
bus = mdio_alloc();
if (!bus)
return NULL;
/* gather only the first mdio bus */
eth_node = dev_read_first_subnode(dev);
node = ofnode_first_subnode(eth_node);
ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
&phandle);
mdio_node = ofnode_get_parent(phandle.node);
for (i = 0; i < TARGET_MDIO_MAX; i++) {
if (ofnode_read_resource(mdio_node, i, &res)) {
pr_err("%s: get OF resource failed\n", __func__);
return NULL;
}
faddr = cpu_to_fdt32(res.start);
phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
phy_size[i] = res.end - res.start;
}
strcpy(bus->name, "miim-internal");
miim[mdiobus_id].regs = ioremap(phy_base[mdiobus_id],
phy_size[mdiobus_id]);
bus->priv = &miim[mdiobus_id];
bus->read = mscc_miim_read;
bus->write = mscc_miim_write;
if (mdio_register(bus))
return NULL;
else
return bus;
}
static void luton_stop(struct udevice *dev)
{
struct luton_private *priv = dev_get_priv(dev);
/*
* Switch core only reset affects VCORE-III bus and MIPS frequency
* and thereby also the DDR SDRAM controller. The workaround is to
* not to redirect any trafic to the CPU after the data transfer.
*/
writel(GENMASK(9, 2), priv->regs[SYS] + SYS_SCH_CPU);
}
static void luton_cpu_capture_setup(struct luton_private *priv)
{
int i;
/* map the 8 CPU extraction queues to CPU port 26 */
writel(0x0, priv->regs[SYS] + SYS_SCH_CPU);
for (i = 0; i <= 1; i++) {
/*
* One to one mapping from CPU Queue number to Group extraction
* number
*/
writel(QS_XTR_MAP_ENA | (QS_XTR_MAP_GRP * i),
priv->regs[QS] + QS_XTR_MAP(i));
/* Enable IFH insertion/parsing on CPU ports */
setbits_le32(priv->regs[REW] + REW_PORT_CFG(CPU_PORT + i),
REW_PORT_CFG_IFH_INSERT_ENA);
/* Enable IFH parsing on CPU port 0 and 1 */
setbits_le32(priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i),
SYS_PORT_MODE_INCL_INJ_HDR);
}
/* Make VLAN aware for CPU traffic */
writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID,
priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
/* Disable learning (only RECV_ENA must be set) */
writel(ANA_PORT_PORT_CFG_RECV_ENA,
priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
/* Enable switching to/from cpu port */
setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(CPU_PORT),
SYS_SWITCH_PORT_MODE_PORT_ENA);
setbits_le32(priv->regs[SYS] + SYS_EGR_NO_SHARING, BIT(CPU_PORT));
}
static void luton_gmii_port_init(struct luton_private *priv, int port)
{
void __iomem *regs = priv->regs[port];
writel(0, regs + DEV_GMII_PORT_MODE_CLK);
/* Enable MAC RX and TX */
writel(DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA |
DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA,
regs + DEV_GMII_MAC_CFG_MAC_ENA);
/* Make VLAN aware for CPU traffic */
writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID,
priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
/* Enable switching to/from port */
setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
SYS_SWITCH_PORT_MODE_PORT_ENA);
}
static void luton_port_init(struct luton_private *priv, int port)
{
void __iomem *regs = priv->regs[port];
writel(0, regs + DEV_PORT_MODE_CLK);
/* Enable MAC RX and TX */
writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
DEV_MAC_CFG_MAC_ENA_TX_ENA,
regs + DEV_MAC_CFG_MAC_ENA);
/* Make VLAN aware for CPU traffic */
writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID,
priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
/* Enable switching to/from port */
setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
SYS_SWITCH_PORT_MODE_PORT_ENA);
}
static void luton_ext_port_init(struct luton_private *priv, int port)
{
void __iomem *regs = priv->regs[port];
/* Enable PCS */
writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
regs + DEV_PCS1G_CFG_PCS1G_CFG);
/* Disable Signal Detect */
writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
/* Enable MAC RX and TX */
writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
DEV_MAC_CFG_MAC_ENA_TX_ENA,
regs + DEV_MAC_CFG_MAC_ENA);
/* Clear sgmii_mode_ena */
writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
/*
* Clear sw_resolve_ena(bit 0) and set adv_ability to
* something meaningful just in case
*/
writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
regs + DEV_PCS1G_CFG_PCS1G_ANEG);
/* Set MAC IFG Gaps */
writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(7) |
DEV_MAC_CFG_MAC_IFG_RX_IFG1(1) |
DEV_MAC_CFG_MAC_IFG_RX_IFG2(5),
regs + DEV_MAC_CFG_MAC_IFG);
/* Set link speed and release all resets */
writel(DEV_PORT_MODE_CLK_LINK_SPEED_1000,
regs + DEV_PORT_MODE_CLK);
/* Make VLAN aware for CPU traffic */
writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID,
priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
/* Enable switching to/from port */
setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
SYS_SWITCH_PORT_MODE_PORT_ENA);
}
static void serdes6g_write(struct luton_private *priv, u32 addr)
{
u32 data;
writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
HSIO_MCB_SERDES6G_CFG_ADDR(addr),
priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
do {
data = readl(priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
} while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
mdelay(100);
}
static void serdes6g_cfg(struct luton_private *priv)
{
writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
HSIO_RCOMP_CFG_CFG0_RUN_CAL,
priv->regs[HSIO] + HSIO_RCOMP_CFG_CFG0);
while (readl(priv->regs[HSIO] + HSIO_RCOMP_STATUS) &
HSIO_RCOMP_STATUS_BUSY)
;
writel(HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(0xb) |
HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H |
HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG);
writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG);
writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_DES_CFG);
writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
/*
* There are 4 serdes6g, configure all except serdes6g0, therefore
* the address is b1110
*/
serdes6g_write(priv, 0xe);
writel(readl(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
serdes6g_write(priv, 0xe);
clrbits_le32(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
priv->regs[HSIO] + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
serdes6g_write(priv, 0xe);
}
static int luton_switch_init(struct luton_private *priv)
{
setbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
clrbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
/* Reset switch & memories */
writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
/* Wait to complete */
if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
printf("Timeout in memory reset\n");
}
/* Enable switch core */
setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
SYS_SYSTEM_RST_CORE_ENA);
/* Setup the Serdes6g macros */
serdes6g_cfg(priv);
return 0;
}
static int luton_initialize(struct luton_private *priv)
{
int ret, i;
/* Initialize switch memories, enable core */
ret = luton_switch_init(priv);
if (ret)
return ret;
/*
* Disable port-to-port by switching
* Put front ports in "port isolation modes" - i.e. they can't send
* to other ports - via the PGID sorce masks.
*/
for (i = 0; i < MAX_PORT; i++)
writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
/* Flush queues */
mscc_flush(priv->regs[QS], luton_regs_qs);
/* Setup frame ageing - "2 sec" - The unit is 4ns on Luton*/
writel(2000000000 / 4,
priv->regs[SYS] + SYS_FRM_AGING);
for (i = PORT0; i < MAX_PORT; i++) {
if (i < PORT10)
luton_gmii_port_init(priv, i);
else
if (i == PORT10 || i == PORT11)
luton_port_init(priv, i);
else
luton_ext_port_init(priv, i);
}
luton_cpu_capture_setup(priv);
return 0;
}
static int luton_write_hwaddr(struct udevice *dev)
{
struct luton_private *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
pdata->enetaddr, PGID_UNICAST);
writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
return 0;
}
static int luton_start(struct udevice *dev)
{
struct luton_private *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
0xff };
int ret;
ret = luton_initialize(priv);
if (ret)
return ret;
/* Set MAC address tables entries for CPU redirection */
mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
mac, PGID_BROADCAST);
writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
pdata->enetaddr, PGID_UNICAST);
writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
return 0;
}
static int luton_send(struct udevice *dev, void *packet, int length)
{
struct luton_private *priv = dev_get_priv(dev);
u32 ifh[IFH_LEN];
int port = BIT(0); /* use port 0 */
u32 *buf = packet;
ifh[0] = IFH_INJ_BYPASS | port;
ifh[1] = (IFH_TAG_TYPE_C << 16);
return mscc_send(priv->regs[QS], luton_regs_qs,
ifh, IFH_LEN, buf, length);
}
static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
{
struct luton_private *priv = dev_get_priv(dev);
u32 *rxbuf = (u32 *)net_rx_packets[0];
int byte_cnt = 0;
byte_cnt = mscc_recv(priv->regs[QS], luton_regs_qs, rxbuf, IFH_LEN,
true);
*packetp = net_rx_packets[0];
return byte_cnt;
}
static int luton_probe(struct udevice *dev)
{
struct luton_private *priv = dev_get_priv(dev);
int i;
struct {
enum luton_target id;
char *name;
} reg[] = {
{ PORT0, "port0" },
{ PORT1, "port1" },
{ PORT2, "port2" },
{ PORT3, "port3" },
{ PORT4, "port4" },
{ PORT5, "port5" },
{ PORT6, "port6" },
{ PORT7, "port7" },
{ PORT8, "port8" },
{ PORT9, "port9" },
{ PORT10, "port10" },
{ PORT11, "port11" },
{ PORT12, "port12" },
{ PORT13, "port13" },
{ PORT14, "port14" },
{ PORT15, "port15" },
{ PORT16, "port16" },
{ PORT17, "port17" },
{ PORT18, "port18" },
{ PORT19, "port19" },
{ PORT20, "port20" },
{ PORT21, "port21" },
{ PORT22, "port22" },
{ PORT23, "port23" },
{ SYS, "sys" },
{ ANA, "ana" },
{ REW, "rew" },
{ GCB, "gcb" },
{ QS, "qs" },
{ HSIO, "hsio" },
};
if (!priv)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(reg); i++) {
priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
if (!priv->regs[reg[i].id]) {
debug
("Error can't get regs base addresses for %s\n",
reg[i].name);
return -ENOMEM;
}
}
/* Release reset in the CU-PHY */
writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
/* Ports with ext phy don't need to reset clk */
for (i = PORT0; i < MAX_INT_PORT; i++) {
if (i < PORT10)
clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
DEV_GMII_PORT_MODE_CLK_PHY_RST);
else
clrbits_le32(priv->regs[i] + DEV_PORT_MODE_CLK,
DEV_PORT_MODE_CLK_PHY_RST);
}
/* Wait for internal PHY to be ready */
if (wait_for_bit_le32(priv->regs[GCB] + GCB_MISC_STAT,
GCB_MISC_STAT_PHY_READY, true, 500, false))
return -EACCES;
priv->bus[INTERNAL] = luton_mdiobus_init(dev, INTERNAL);
for (i = 0; i < MAX_INT_PORT; i++) {
phy_connect(priv->bus[INTERNAL], i, dev,
PHY_INTERFACE_MODE_NONE);
}
/*
* coma_mode is need on only one phy, because all the other phys
* will be affected.
*/
mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0x10);
mscc_miim_write(priv->bus[INTERNAL], 0, 0, 14, 0x800);
mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0);
return 0;
}
static int luton_remove(struct udevice *dev)
{
struct luton_private *priv = dev_get_priv(dev);
int i;
for (i = 0; i < NUM_PHY; i++) {
mdio_unregister(priv->bus[i]);
mdio_free(priv->bus[i]);
}
return 0;
}
static const struct eth_ops luton_ops = {
.start = luton_start,
.stop = luton_stop,
.send = luton_send,
.recv = luton_recv,
.write_hwaddr = luton_write_hwaddr,
};
static const struct udevice_id mscc_luton_ids[] = {
{.compatible = "mscc,vsc7527-switch", },
{ /* Sentinel */ }
};
U_BOOT_DRIVER(luton) = {
.name = "luton-switch",
.id = UCLASS_ETH,
.of_match = mscc_luton_ids,
.probe = luton_probe,
.remove = luton_remove,
.ops = &luton_ops,
.priv_auto_alloc_size = sizeof(struct luton_private),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
};

View File

@ -0,0 +1,74 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2018 Microsemi Corporation
*/
#include <linux/io.h>
#include "mscc_mac_table.h"
#define ANA_TABLES_MACACCESS_VALID BIT(11)
#define ANA_TABLES_MACACCESS_ENTRYTYPE(x) ((x) << 9)
#define ANA_TABLES_MACACCESS_DEST_IDX(x) ((x) << 3)
#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x) (x)
#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M GENMASK(2, 0)
#define MACACCESS_CMD_IDLE 0
#define MACACCESS_CMD_LEARN 1
/* MAC table entry types.
* ENTRYTYPE_NORMAL is subject to aging.
* ENTRYTYPE_LOCKED is not subject to aging.
*/
enum macaccess_entry_type {
ENTRYTYPE_NORMAL = 0,
ENTRYTYPE_LOCKED,
};
static int vlan_wait_for_completion(void __iomem *regs,
const unsigned long *mscc_mac_table_offset)
{
unsigned int val, timeout = 10;
/* Wait for the issued mac table command to be completed, or timeout.
* When the command read from ANA_TABLES_MACACCESS is
* MACACCESS_CMD_IDLE, the issued command completed successfully.
*/
do {
val = readl(regs +
mscc_mac_table_offset[MSCC_ANA_TABLES_MACACCESS]);
val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M;
} while (val != MACACCESS_CMD_IDLE && timeout--);
if (!timeout)
return -ETIMEDOUT;
return 0;
}
int mscc_mac_table_add(void __iomem *regs,
const unsigned long *mscc_mac_table_offset,
const unsigned char mac[ETH_LEN], int pgid)
{
u32 macl = 0, mach = 0;
/* Set the MAC address to handle and the vlan associated in a format
* understood by the hardware.
*/
mach |= MAC_VID << 16;
mach |= ((u32)mac[0]) << 8;
mach |= ((u32)mac[1]) << 0;
macl |= ((u32)mac[2]) << 24;
macl |= ((u32)mac[3]) << 16;
macl |= ((u32)mac[4]) << 8;
macl |= ((u32)mac[5]) << 0;
writel(macl, regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACLDATA]);
writel(mach, regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACHDATA]);
writel(ANA_TABLES_MACACCESS_VALID |
ANA_TABLES_MACACCESS_DEST_IDX(pgid) |
ANA_TABLES_MACACCESS_ENTRYTYPE(ENTRYTYPE_LOCKED) |
ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACACCESS]);
return vlan_wait_for_completion(regs, mscc_mac_table_offset);
}

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2018 Microsemi Corporation
*/
#include <common.h>
#define ETH_LEN 6
#define MAC_VID 1
enum mscc_regs_ana_table {
MSCC_ANA_TABLES_MACHDATA,
MSCC_ANA_TABLES_MACLDATA,
MSCC_ANA_TABLES_MACACCESS,
};
int mscc_mac_table_add(void __iomem *regs,
const unsigned long *mscc_mac_table_offset,
const unsigned char mac[ETH_LEN], int pgid);

View File

@ -0,0 +1,74 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2018 Microsemi Corporation
*/
#include <miiphy.h>
#include <wait_bit.h>
#include "mscc_miim.h"
#define MIIM_STATUS 0x0
#define MIIM_STAT_BUSY BIT(3)
#define MIIM_CMD 0x8
#define MIIM_CMD_SCAN BIT(0)
#define MIIM_CMD_OPR_WRITE BIT(1)
#define MIIM_CMD_OPR_READ BIT(2)
#define MIIM_CMD_SINGLE_SCAN BIT(3)
#define MIIM_CMD_WRDATA(x) ((x) << 4)
#define MIIM_CMD_REGAD(x) ((x) << 20)
#define MIIM_CMD_PHYAD(x) ((x) << 25)
#define MIIM_CMD_VLD BIT(31)
#define MIIM_DATA 0xC
#define MIIM_DATA_ERROR (0x2 << 16)
static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
{
return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STAT_BUSY,
false, 250, false);
}
int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
u32 val;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ,
miim->regs + MIIM_CMD);
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
val = readl(miim->regs + MIIM_DATA);
if (val & MIIM_DATA_ERROR) {
ret = -EIO;
goto out;
}
ret = val & 0xFFFF;
out:
return ret;
}
int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
u16 val)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret < 0)
goto out;
writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) |
MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD);
out:
return ret;
}

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2018 Microsemi Corporation
*/
struct mscc_miim_dev {
void __iomem *regs;
void __iomem *phy_regs;
};
int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg);
int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, u16 val);

View File

@ -0,0 +1,139 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2018 Microsemi Corporation
*/
#include <linux/io.h>
#include "mscc_xfer.h"
#define QS_XTR_FLUSH_FLUSH GENMASK(1, 0)
#define QS_INJ_CTRL_GAP_SIZE(x) ((x) << 21)
#define QS_INJ_CTRL_EOF BIT(19)
#define QS_INJ_CTRL_SOF BIT(18)
#define QS_INJ_CTRL_VLD_BYTES(x) ((x) << 16)
#define XTR_EOF_0 ntohl(0x80000000u)
#define XTR_EOF_1 ntohl(0x80000001u)
#define XTR_EOF_2 ntohl(0x80000002u)
#define XTR_EOF_3 ntohl(0x80000003u)
#define XTR_PRUNED ntohl(0x80000004u)
#define XTR_ABORT ntohl(0x80000005u)
#define XTR_ESCAPE ntohl(0x80000006u)
#define XTR_NOT_READY ntohl(0x80000007u)
#define BUF_CELL_SZ 60
#define XTR_VALID_BYTES(x) (4 - ((x) & 3))
int mscc_send(void __iomem *regs, const unsigned long *mscc_qs_offset,
u32 *ifh, size_t ifh_len, u32 *buff, size_t buff_len)
{
int i, count = (buff_len + 3) / 4, last = buff_len % 4;
writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
for (i = 0; i < ifh_len; i++)
writel(ifh[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
for (i = 0; i < count; i++)
writel(buff[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
/* Add padding */
while (i < (BUF_CELL_SZ / 4)) {
writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
i++;
}
/* Indicate EOF and valid bytes in last word */
writel(QS_INJ_CTRL_GAP_SIZE(1) |
QS_INJ_CTRL_VLD_BYTES(buff_len < BUF_CELL_SZ ? 0 : last) |
QS_INJ_CTRL_EOF, regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
/* Add dummy CRC */
writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
return 0;
}
int mscc_recv(void __iomem *regs, const unsigned long *mscc_qs_offset,
u32 *rxbuf, size_t ifh_len, bool byte_swap)
{
u8 grp = 0; /* Recv everything on CPU group 0 */
int i, byte_cnt = 0;
bool eof_flag = false, pruned_flag = false, abort_flag = false;
if (!(readl(regs + mscc_qs_offset[MSCC_QS_XTR_DATA_PRESENT]) &
BIT(grp)))
return -EAGAIN;
/* skip IFH */
for (i = 0; i < ifh_len; i++)
readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
while (!eof_flag) {
u32 val = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
u32 cmp = val;
if (byte_swap)
cmp = ntohl(val);
switch (cmp) {
case XTR_NOT_READY:
debug("%d NOT_READY...?\n", byte_cnt);
break;
case XTR_ABORT:
*rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
abort_flag = true;
eof_flag = true;
debug("XTR_ABORT\n");
break;
case XTR_EOF_0:
case XTR_EOF_1:
case XTR_EOF_2:
case XTR_EOF_3:
byte_cnt += XTR_VALID_BYTES(val);
*rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
eof_flag = true;
debug("EOF\n");
break;
case XTR_PRUNED:
/* But get the last 4 bytes as well */
eof_flag = true;
pruned_flag = true;
debug("PRUNED\n");
/* fallthrough */
case XTR_ESCAPE:
*rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
byte_cnt += 4;
rxbuf++;
debug("ESCAPED\n");
break;
default:
*rxbuf = val;
byte_cnt += 4;
rxbuf++;
}
}
if (abort_flag || pruned_flag || !eof_flag) {
debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
abort_flag, pruned_flag, eof_flag);
return -EAGAIN;
}
return byte_cnt;
}
void mscc_flush(void __iomem *regs, const unsigned long *mscc_qs_offset)
{
/* All Queues flush */
setbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
QS_XTR_FLUSH_FLUSH);
/* Allow to drain */
mdelay(1);
/* All Queues normal */
clrbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
QS_XTR_FLUSH_FLUSH);
}

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2018 Microsemi Corporation
*/
#include <common.h>
enum mscc_regs_qs {
MSCC_QS_XTR_RD,
MSCC_QS_XTR_FLUSH,
MSCC_QS_XTR_DATA_PRESENT,
MSCC_QS_INJ_WR,
MSCC_QS_INJ_CTRL,
};
int mscc_send(void __iomem *regs, const unsigned long *mscc_qs_offset,
u32 *ifh, size_t ifh_len, u32 *buff, size_t buff_len);
int mscc_recv(void __iomem *regs, const unsigned long *mscc_qs_offset,
u32 *rxbuf, size_t ifh_len, bool byte_swap);
void mscc_flush(void __iomem *regs, const unsigned long *mscc_qs_offset);

View File

@ -15,19 +15,9 @@
#include <net.h> #include <net.h>
#include <wait_bit.h> #include <wait_bit.h>
#define MIIM_STATUS 0x0 #include "mscc_miim.h"
#define MIIM_STAT_BUSY BIT(3) #include "mscc_xfer.h"
#define MIIM_CMD 0x8 #include "mscc_mac_table.h"
#define MIIM_CMD_SCAN BIT(0)
#define MIIM_CMD_OPR_WRITE BIT(1)
#define MIIM_CMD_OPR_READ BIT(2)
#define MIIM_CMD_SINGLE_SCAN BIT(3)
#define MIIM_CMD_WRDATA(x) ((x) << 4)
#define MIIM_CMD_REGAD(x) ((x) << 20)
#define MIIM_CMD_PHYAD(x) ((x) << 25)
#define MIIM_CMD_VLD BIT(31)
#define MIIM_DATA 0xC
#define MIIM_DATA_ERROR (0x2 << 16)
#define PHY_CFG 0x0 #define PHY_CFG 0x0
#define PHY_CFG_ENA 0xF #define PHY_CFG_ENA 0xF
@ -41,17 +31,6 @@
#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) #define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
#define ANA_PORT_PORT_CFG(x) (0x7070 + 0x100 * (x)) #define ANA_PORT_PORT_CFG(x) (0x7070 + 0x100 * (x))
#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6) #define ANA_PORT_PORT_CFG_RECV_ENA BIT(6)
#define ANA_TABLES_MACHDATA 0x8b34
#define ANA_TABLES_MACLDATA 0x8b38
#define ANA_TABLES_MACACCESS 0x8b3c
#define ANA_TABLES_MACACCESS_VALID BIT(11)
#define ANA_TABLES_MACACCESS_ENTRYTYPE(x) ((x) << 9)
#define ANA_TABLES_MACACCESS_DEST_IDX(x) ((x) << 3)
#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x) (x)
#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M GENMASK(2, 0)
#define MACACCESS_CMD_IDLE 0
#define MACACCESS_CMD_LEARN 1
#define MACACCESS_CMD_GET_NEXT 4
#define ANA_PGID(x) (0x8c00 + 4 * (x)) #define ANA_PGID(x) (0x8c00 + 4 * (x))
#define SYS_FRM_AGING 0x574 #define SYS_FRM_AGING 0x574
@ -99,37 +78,16 @@
#define QS_XTR_GRP_CFG_MODE(x) ((x) << 2) #define QS_XTR_GRP_CFG_MODE(x) ((x) << 2)
#define QS_XTR_GRP_CFG_STATUS_WORD_POS BIT(1) #define QS_XTR_GRP_CFG_STATUS_WORD_POS BIT(1)
#define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0) #define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0)
#define QS_XTR_RD(x) (0x8 + 4 * (x))
#define QS_XTR_FLUSH 0x18
#define QS_XTR_FLUSH_FLUSH GENMASK(1, 0)
#define QS_XTR_DATA_PRESENT 0x1c
#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4) #define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
#define QS_INJ_GRP_CFG_MODE(x) ((x) << 2) #define QS_INJ_GRP_CFG_MODE(x) ((x) << 2)
#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0) #define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0)
#define QS_INJ_WR(x) (0x2c + 4 * (x))
#define QS_INJ_CTRL(x) (0x34 + 4 * (x))
#define QS_INJ_CTRL_GAP_SIZE(x) ((x) << 21)
#define QS_INJ_CTRL_EOF BIT(19)
#define QS_INJ_CTRL_SOF BIT(18)
#define QS_INJ_CTRL_VLD_BYTES(x) ((x) << 16)
#define XTR_EOF_0 ntohl(0x80000000u)
#define XTR_EOF_1 ntohl(0x80000001u)
#define XTR_EOF_2 ntohl(0x80000002u)
#define XTR_EOF_3 ntohl(0x80000003u)
#define XTR_PRUNED ntohl(0x80000004u)
#define XTR_ABORT ntohl(0x80000005u)
#define XTR_ESCAPE ntohl(0x80000006u)
#define XTR_NOT_READY ntohl(0x80000007u)
#define IFH_INJ_BYPASS BIT(31) #define IFH_INJ_BYPASS BIT(31)
#define IFH_TAG_TYPE_C 0 #define IFH_TAG_TYPE_C 0
#define XTR_VALID_BYTES(x) (4 - ((x) & 3))
#define MAC_VID 1 #define MAC_VID 1
#define CPU_PORT 11 #define CPU_PORT 11
#define INTERNAL_PORT_MSK 0xF #define INTERNAL_PORT_MSK 0xF
#define IFH_LEN 4 #define IFH_LEN 4
#define OCELOT_BUF_CELL_SZ 60
#define ETH_ALEN 6 #define ETH_ALEN 6
#define PGID_BROADCAST 13 #define PGID_BROADCAST 13
#define PGID_UNICAST 14 #define PGID_UNICAST 14
@ -151,19 +109,6 @@ enum ocelot_target {
#define MAX_PORT (PORT3 - PORT0) #define MAX_PORT (PORT3 - PORT0)
/* MAC table entry types.
* ENTRYTYPE_NORMAL is subject to aging.
* ENTRYTYPE_LOCKED is not subject to aging.
* ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
* ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
*/
enum macaccess_entry_type {
ENTRYTYPE_NORMAL = 0,
ENTRYTYPE_LOCKED,
ENTRYTYPE_MACv4,
ENTRYTYPE_MACv6,
};
enum ocelot_mdio_target { enum ocelot_mdio_target {
MIIM, MIIM,
PHY, PHY,
@ -178,33 +123,24 @@ enum ocelot_phy_id {
struct ocelot_private { struct ocelot_private {
void __iomem *regs[TARGET_MAX]; void __iomem *regs[TARGET_MAX];
struct mii_dev *bus[NUM_PHY]; struct mii_dev *bus[NUM_PHY];
struct phy_device *phydev;
int phy_mode;
int max_speed;
int rx_pos;
int rx_siz;
int rx_off;
int tx_num;
u8 tx_adj_packetbuf[PKTSIZE_ALIGN + PKTALIGN];
void *tx_adj_buf;
}; };
struct mscc_miim_dev { static const unsigned long ocelot_regs_qs[] = {
void __iomem *regs; [MSCC_QS_XTR_RD] = 0x8,
void __iomem *phy_regs; [MSCC_QS_XTR_FLUSH] = 0x18,
[MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
[MSCC_QS_INJ_WR] = 0x2c,
[MSCC_QS_INJ_CTRL] = 0x34,
}; };
struct mscc_miim_dev miim[NUM_PHY]; static const unsigned long ocelot_regs_ana_table[] = {
[MSCC_ANA_TABLES_MACHDATA] = 0x8b34,
[MSCC_ANA_TABLES_MACLDATA] = 0x8b38,
[MSCC_ANA_TABLES_MACACCESS] = 0x8b3c,
};
static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) static struct mscc_miim_dev miim[NUM_PHY];
{
return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STAT_BUSY,
false, 250, false);
}
static int mscc_miim_reset(struct mii_dev *bus) static int mscc_miim_reset(struct mii_dev *bus)
{ {
@ -220,52 +156,6 @@ static int mscc_miim_reset(struct mii_dev *bus)
return 0; return 0;
} }
static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
u32 val;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ,
miim->regs + MIIM_CMD);
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
val = readl(miim->regs + MIIM_DATA);
if (val & MIIM_DATA_ERROR) {
ret = -EIO;
goto out;
}
ret = val & 0xFFFF;
out:
return ret;
}
static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
u16 val)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret < 0)
goto out;
writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) |
MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD);
out:
return ret;
}
/* For now only setup the internal mdio bus */ /* For now only setup the internal mdio bus */
static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev) static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev)
{ {
@ -436,16 +326,6 @@ static int ocelot_switch_init(struct ocelot_private *priv)
return 0; return 0;
} }
static void ocelot_switch_flush(struct ocelot_private *priv)
{
/* All Queues flush */
setbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
/* Allow to drain */
mdelay(1);
/* All Queues normal */
clrbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
}
static int ocelot_initialize(struct ocelot_private *priv) static int ocelot_initialize(struct ocelot_private *priv)
{ {
int ret, i; int ret, i;
@ -463,7 +343,7 @@ static int ocelot_initialize(struct ocelot_private *priv)
writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i)); writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
/* Flush queues */ /* Flush queues */
ocelot_switch_flush(priv); mscc_flush(priv->regs[QS], ocelot_regs_qs);
/* Setup frame ageing - "2 sec" - The unit is 6.5us on Ocelot */ /* Setup frame ageing - "2 sec" - The unit is 6.5us on Ocelot */
writel(SYS_FRM_AGING_ENA | (20000000 / 65), writel(SYS_FRM_AGING_ENA | (20000000 / 65),
@ -479,62 +359,13 @@ static int ocelot_initialize(struct ocelot_private *priv)
return 0; return 0;
} }
static inline int ocelot_vlant_wait_for_completion(struct ocelot_private *priv)
{
unsigned int val, timeout = 10;
/* Wait for the issued mac table command to be completed, or timeout.
* When the command read from ANA_TABLES_MACACCESS is
* MACACCESS_CMD_IDLE, the issued command completed successfully.
*/
do {
val = readl(priv->regs[ANA] + ANA_TABLES_MACACCESS);
val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M;
} while (val != MACACCESS_CMD_IDLE && timeout--);
if (!timeout)
return -ETIMEDOUT;
return 0;
}
static int ocelot_mac_table_add(struct ocelot_private *priv,
const unsigned char mac[ETH_ALEN], int pgid)
{
u32 macl = 0, mach = 0;
int ret;
/* Set the MAC address to handle and the vlan associated in a format
* understood by the hardware.
*/
mach |= MAC_VID << 16;
mach |= ((u32)mac[0]) << 8;
mach |= ((u32)mac[1]) << 0;
macl |= ((u32)mac[2]) << 24;
macl |= ((u32)mac[3]) << 16;
macl |= ((u32)mac[4]) << 8;
macl |= ((u32)mac[5]) << 0;
writel(macl, priv->regs[ANA] + ANA_TABLES_MACLDATA);
writel(mach, priv->regs[ANA] + ANA_TABLES_MACHDATA);
writel(ANA_TABLES_MACACCESS_VALID |
ANA_TABLES_MACACCESS_DEST_IDX(pgid) |
ANA_TABLES_MACACCESS_ENTRYTYPE(ENTRYTYPE_LOCKED) |
ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
priv->regs[ANA] + ANA_TABLES_MACACCESS);
ret = ocelot_vlant_wait_for_completion(priv);
return ret;
}
static int ocelot_write_hwaddr(struct udevice *dev) static int ocelot_write_hwaddr(struct udevice *dev)
{ {
struct ocelot_private *priv = dev_get_priv(dev); struct ocelot_private *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev); struct eth_pdata *pdata = dev_get_platdata(dev);
ocelot_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST); mscc_mac_table_add(priv->regs[ANA], ocelot_regs_ana_table,
pdata->enetaddr, PGID_UNICAST);
writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST)); writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
@ -554,13 +385,15 @@ static int ocelot_start(struct udevice *dev)
return ret; return ret;
/* Set MAC address tables entries for CPU redirection */ /* Set MAC address tables entries for CPU redirection */
ocelot_mac_table_add(priv, mac, PGID_BROADCAST); mscc_mac_table_add(priv->regs[ANA], ocelot_regs_ana_table, mac,
PGID_BROADCAST);
writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK, writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
priv->regs[ANA] + ANA_PGID(PGID_BROADCAST)); priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
/* It should be setup latter in ocelot_write_hwaddr */ /* It should be setup latter in ocelot_write_hwaddr */
ocelot_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST); mscc_mac_table_add(priv->regs[ANA], ocelot_regs_ana_table,
pdata->enetaddr, PGID_UNICAST);
writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST)); writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
@ -572,13 +405,8 @@ static int ocelot_send(struct udevice *dev, void *packet, int length)
struct ocelot_private *priv = dev_get_priv(dev); struct ocelot_private *priv = dev_get_priv(dev);
u32 ifh[IFH_LEN]; u32 ifh[IFH_LEN];
int port = BIT(0); /* use port 0 */ int port = BIT(0); /* use port 0 */
u8 grp = 0; /* Send everything on CPU group 0 */
int i, count = (length + 3) / 4, last = length % 4;
u32 *buf = packet; u32 *buf = packet;
writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
priv->regs[QS] + QS_INJ_CTRL(grp));
/* /*
* Generate the IFH for frame injection * Generate the IFH for frame injection
* *
@ -595,91 +423,18 @@ static int ocelot_send(struct udevice *dev, void *packet, int length)
ifh[2] = (0xff & port) << 24; ifh[2] = (0xff & port) << 24;
ifh[3] = (IFH_TAG_TYPE_C << 16); ifh[3] = (IFH_TAG_TYPE_C << 16);
for (i = 0; i < IFH_LEN; i++) return mscc_send(priv->regs[QS], ocelot_regs_qs,
writel(ifh[i], priv->regs[QS] + QS_INJ_WR(grp)); ifh, IFH_LEN, buf, length);
for (i = 0; i < count; i++)
writel(buf[i], priv->regs[QS] + QS_INJ_WR(grp));
/* Add padding */
while (i < (OCELOT_BUF_CELL_SZ / 4)) {
writel(0, priv->regs[QS] + QS_INJ_WR(grp));
i++;
}
/* Indicate EOF and valid bytes in last word */
writel(QS_INJ_CTRL_GAP_SIZE(1) |
QS_INJ_CTRL_VLD_BYTES(length < OCELOT_BUF_CELL_SZ ? 0 : last) |
QS_INJ_CTRL_EOF, priv->regs[QS] + QS_INJ_CTRL(grp));
/* Add dummy CRC */
writel(0, priv->regs[QS] + QS_INJ_WR(grp));
return 0;
} }
static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp) static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp)
{ {
struct ocelot_private *priv = dev_get_priv(dev); struct ocelot_private *priv = dev_get_priv(dev);
u8 grp = 0; /* Send everything on CPU group 0 */
u32 *rxbuf = (u32 *)net_rx_packets[0]; u32 *rxbuf = (u32 *)net_rx_packets[0];
int i, byte_cnt = 0; int byte_cnt;
bool eof_flag = false, pruned_flag = false, abort_flag = false;
if (!(readl(priv->regs[QS] + QS_XTR_DATA_PRESENT) & BIT(grp))) byte_cnt = mscc_recv(priv->regs[QS], ocelot_regs_qs, rxbuf, IFH_LEN,
return -EAGAIN; false);
/* skip IFH */
for (i = 0; i < IFH_LEN; i++)
readl(priv->regs[QS] + QS_XTR_RD(grp));
while (!eof_flag) {
u32 val = readl(priv->regs[QS] + QS_XTR_RD(grp));
switch (val) {
case XTR_NOT_READY:
debug("%d NOT_READY...?\n", byte_cnt);
break;
case XTR_ABORT:
/* really nedeed?? not done in linux */
*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
abort_flag = true;
eof_flag = true;
debug("XTR_ABORT\n");
break;
case XTR_EOF_0:
case XTR_EOF_1:
case XTR_EOF_2:
case XTR_EOF_3:
byte_cnt += XTR_VALID_BYTES(val);
*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
eof_flag = true;
debug("EOF\n");
break;
case XTR_PRUNED:
/* But get the last 4 bytes as well */
eof_flag = true;
pruned_flag = true;
debug("PRUNED\n");
/* fallthrough */
case XTR_ESCAPE:
*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
byte_cnt += 4;
rxbuf++;
debug("ESCAPED\n");
break;
default:
*rxbuf = val;
byte_cnt += 4;
rxbuf++;
}
}
if (abort_flag || pruned_flag || !eof_flag) {
debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
abort_flag, pruned_flag, eof_flag);
return -EAGAIN;
}
*packetp = net_rx_packets[0]; *packetp = net_rx_packets[0];

View File

@ -7,7 +7,7 @@
#define __CONFIG_GARDENA_SMART_GATEWAY_H #define __CONFIG_GARDENA_SMART_GATEWAY_H
/* CPU */ /* CPU */
#define CONFIG_SYS_MIPS_TIMER_FREQ 200000000 #define CONFIG_SYS_MIPS_TIMER_FREQ 290000000
/* RAM */ /* RAM */
#define CONFIG_SYS_SDRAM_BASE 0x80000000 #define CONFIG_SYS_SDRAM_BASE 0x80000000

View File

@ -7,7 +7,7 @@
#define __CONFIG_LINKIT_SMART_7688_H #define __CONFIG_LINKIT_SMART_7688_H
/* CPU */ /* CPU */
#define CONFIG_SYS_MIPS_TIMER_FREQ 200000000 #define CONFIG_SYS_MIPS_TIMER_FREQ 290000000
/* RAM */ /* RAM */
#define CONFIG_SYS_SDRAM_BASE 0x80000000 #define CONFIG_SYS_SDRAM_BASE 0x80000000