mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-30 16:13:27 +08:00
Merge branch 'master' of git://git.denx.de/u-boot-net
This commit is contained in:
commit
9c94e0a644
@ -123,6 +123,8 @@ config SANDBOX
|
||||
imply DM_SOUND
|
||||
imply PCI_SANDBOX_EP
|
||||
imply PCH
|
||||
imply PHYLIB
|
||||
imply DM_MDIO
|
||||
|
||||
config SH
|
||||
bool "SuperH architecture"
|
||||
|
@ -64,6 +64,7 @@
|
||||
/* MCUSS Range */
|
||||
<0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>,
|
||||
<0x00 0x40200000 0x00 0x40200000 0x00 0x00900100>,
|
||||
<0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>,
|
||||
<0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>,
|
||||
<0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>,
|
||||
<0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>,
|
||||
@ -75,6 +76,7 @@
|
||||
#size-cells = <2>;
|
||||
ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, /* MCU NAVSS*/
|
||||
<0x00 0x40200000 0x00 0x40200000 0x00 0x00900100>, /* First peripheral window */
|
||||
<0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, /* CTRL_MMR0 */
|
||||
<0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, /* WKUP */
|
||||
<0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, /* MMRs, remaining NAVSS */
|
||||
<0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, /* CPSW */
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <dt-bindings/pinctrl/k3.h>
|
||||
#include <dt-bindings/dma/k3-udma.h>
|
||||
#include <dt-bindings/net/ti-dp83867.h>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
@ -13,6 +14,7 @@
|
||||
|
||||
aliases {
|
||||
serial2 = &main_uart0;
|
||||
ethernet0 = &cpsw_port1;
|
||||
};
|
||||
};
|
||||
|
||||
@ -110,6 +112,116 @@
|
||||
dma-coherent;
|
||||
};
|
||||
};
|
||||
|
||||
mcu_conf: scm_conf@40f00000 {
|
||||
compatible = "syscon";
|
||||
reg = <0x0 0x40f00000 0x0 0x20000>;
|
||||
};
|
||||
|
||||
mcu_cpsw: cpsw_nuss@046000000 {
|
||||
compatible = "ti,am654-cpsw-nuss";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
reg = <0x0 0x46000000 0x0 0x200000>;
|
||||
reg-names = "cpsw_nuss";
|
||||
ranges;
|
||||
dma-coherent;
|
||||
clocks = <&k3_clks 5 10>;
|
||||
clock-names = "fck";
|
||||
power-domains = <&k3_pds 5>;
|
||||
ti,psil-base = <0x7000>;
|
||||
|
||||
dmas = <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_TX>,
|
||||
<&mcu_udmap &mcu_cpsw 1 UDMA_DIR_TX>,
|
||||
<&mcu_udmap &mcu_cpsw 2 UDMA_DIR_TX>,
|
||||
<&mcu_udmap &mcu_cpsw 3 UDMA_DIR_TX>,
|
||||
<&mcu_udmap &mcu_cpsw 4 UDMA_DIR_TX>,
|
||||
<&mcu_udmap &mcu_cpsw 5 UDMA_DIR_TX>,
|
||||
<&mcu_udmap &mcu_cpsw 6 UDMA_DIR_TX>,
|
||||
<&mcu_udmap &mcu_cpsw 7 UDMA_DIR_TX>,
|
||||
<&mcu_udmap &mcu_cpsw 0 UDMA_DIR_RX>;
|
||||
dma-names = "tx0", "tx1", "tx2", "tx3",
|
||||
"tx4", "tx5", "tx6", "tx7",
|
||||
"rx";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
host: host@0 {
|
||||
reg = <0>;
|
||||
ti,label = "host";
|
||||
};
|
||||
|
||||
cpsw_port1: port@1 {
|
||||
reg = <1>;
|
||||
ti,mac-only;
|
||||
ti,label = "port1";
|
||||
ti,syscon-efuse = <&mcu_conf 0x200>;
|
||||
};
|
||||
};
|
||||
|
||||
davinci_mdio: mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
bus_freq = <1000000>;
|
||||
};
|
||||
|
||||
ti,psil-config0 {
|
||||
linux,udma-mode = <UDMA_PKT_MODE>;
|
||||
statictr-type = <PSIL_STATIC_TR_NONE>;
|
||||
ti,needs-epib;
|
||||
ti,psd-size = <16>;
|
||||
};
|
||||
|
||||
ti,psil-config1 {
|
||||
linux,udma-mode = <UDMA_PKT_MODE>;
|
||||
statictr-type = <PSIL_STATIC_TR_NONE>;
|
||||
ti,needs-epib;
|
||||
ti,psd-size = <16>;
|
||||
};
|
||||
|
||||
ti,psil-config2 {
|
||||
linux,udma-mode = <UDMA_PKT_MODE>;
|
||||
statictr-type = <PSIL_STATIC_TR_NONE>;
|
||||
ti,needs-epib;
|
||||
ti,psd-size = <16>;
|
||||
};
|
||||
|
||||
ti,psil-config3 {
|
||||
linux,udma-mode = <UDMA_PKT_MODE>;
|
||||
statictr-type = <PSIL_STATIC_TR_NONE>;
|
||||
ti,needs-epib;
|
||||
ti,psd-size = <16>;
|
||||
};
|
||||
|
||||
ti,psil-config4 {
|
||||
linux,udma-mode = <UDMA_PKT_MODE>;
|
||||
statictr-type = <PSIL_STATIC_TR_NONE>;
|
||||
ti,needs-epib;
|
||||
ti,psd-size = <16>;
|
||||
};
|
||||
|
||||
ti,psil-config5 {
|
||||
linux,udma-mode = <UDMA_PKT_MODE>;
|
||||
statictr-type = <PSIL_STATIC_TR_NONE>;
|
||||
ti,needs-epib;
|
||||
ti,psd-size = <16>;
|
||||
};
|
||||
|
||||
ti,psil-config6 {
|
||||
linux,udma-mode = <UDMA_PKT_MODE>;
|
||||
statictr-type = <PSIL_STATIC_TR_NONE>;
|
||||
ti,needs-epib;
|
||||
ti,psd-size = <16>;
|
||||
};
|
||||
|
||||
ti,psil-config7 {
|
||||
linux,udma-mode = <UDMA_PKT_MODE>;
|
||||
statictr-type = <PSIL_STATIC_TR_NONE>;
|
||||
ti,needs-epib;
|
||||
ti,psd-size = <16>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&cbass_wakeup {
|
||||
@ -189,6 +301,32 @@
|
||||
u-boot,dm-spl;
|
||||
};
|
||||
|
||||
&wkup_pmx0 {
|
||||
mcu_cpsw_pins_default: mcu_cpsw_pins_default {
|
||||
pinctrl-single,pins = <
|
||||
AM65X_WKUP_IOPAD(0x0058, PIN_OUTPUT, 0) /* (N4) MCU_RGMII1_TX_CTL */
|
||||
AM65X_WKUP_IOPAD(0x005c, PIN_INPUT, 0) /* (N5) MCU_RGMII1_RX_CTL */
|
||||
AM65X_WKUP_IOPAD(0x0060, PIN_OUTPUT, 0) /* (M2) MCU_RGMII1_TD3 */
|
||||
AM65X_WKUP_IOPAD(0x0064, PIN_OUTPUT, 0) /* (M3) MCU_RGMII1_TD2 */
|
||||
AM65X_WKUP_IOPAD(0x0068, PIN_OUTPUT, 0) /* (M4) MCU_RGMII1_TD1 */
|
||||
AM65X_WKUP_IOPAD(0x006c, PIN_OUTPUT, 0) /* (M5) MCU_RGMII1_TD0 */
|
||||
AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 0) /* (L2) MCU_RGMII1_RD3 */
|
||||
AM65X_WKUP_IOPAD(0x007c, PIN_INPUT, 0) /* (L5) MCU_RGMII1_RD2 */
|
||||
AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 0) /* (M6) MCU_RGMII1_RD1 */
|
||||
AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 0) /* (L6) MCU_RGMII1_RD0 */
|
||||
AM65X_WKUP_IOPAD(0x0070, PIN_INPUT, 0) /* (N1) MCU_RGMII1_TXC */
|
||||
AM65X_WKUP_IOPAD(0x0074, PIN_INPUT, 0) /* (M1) MCU_RGMII1_RXC */
|
||||
>;
|
||||
};
|
||||
|
||||
mcu_mdio_pins_default: mcu_mdio1_pins_default {
|
||||
pinctrl-single,pins = <
|
||||
AM65X_WKUP_IOPAD(0x008c, PIN_OUTPUT, 0) /* (L1) MCU_MDIO0_MDC */
|
||||
AM65X_WKUP_IOPAD(0x0088, PIN_INPUT, 0) /* (L4) MCU_MDIO0_MDIO */
|
||||
>;
|
||||
};
|
||||
};
|
||||
|
||||
&main_uart0 {
|
||||
u-boot,dm-spl;
|
||||
pinctrl-names = "default";
|
||||
@ -212,3 +350,35 @@
|
||||
pinctrl-0 = <&main_mmc1_pins_default>;
|
||||
sdhci-caps-mask = <0x7 0x0>;
|
||||
};
|
||||
|
||||
&mcu_cpsw {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&mcu_cpsw_pins_default &mcu_mdio_pins_default>;
|
||||
};
|
||||
|
||||
&davinci_mdio {
|
||||
phy0: ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
/* TODO: phy reset: TCA9555RTWR(i2c:0x21)[p04].GPIO_MCU_RGMII_RSTN */
|
||||
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
|
||||
ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
|
||||
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
|
||||
};
|
||||
};
|
||||
|
||||
&cpsw_port1 {
|
||||
phy-mode = "rgmii-id";
|
||||
phy-handle = <&phy0>;
|
||||
};
|
||||
|
||||
&mcu_cpsw {
|
||||
reg = <0x0 0x46000000 0x0 0x200000>,
|
||||
<0x0 0x40f00200 0x0 0x2>;
|
||||
reg-names = "cpsw_nuss", "mac_efuse";
|
||||
|
||||
cpsw-phy-sel@40f04040 {
|
||||
compatible = "ti,am654-cpsw-phy-sel";
|
||||
reg= <0x0 0x40f04040 0x0 0x4>;
|
||||
reg-names = "gmii-sel";
|
||||
};
|
||||
};
|
||||
|
@ -823,6 +823,10 @@
|
||||
dmas = <&dma 0>, <&dma 1>, <&dma 2>;
|
||||
dma-names = "m2m", "tx0", "rx0";
|
||||
};
|
||||
|
||||
mdio-test {
|
||||
compatible = "sandbox,mdio";
|
||||
};
|
||||
};
|
||||
|
||||
#include "sandbox_pmic.dtsi"
|
||||
|
@ -203,6 +203,11 @@ static int do_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
#ifdef CONFIG_DM_MDIO
|
||||
/* probe DM MII device before any operation so they are all accesible */
|
||||
dm_mdio_probe_devices();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We use the last specified parameters, unless new ones are
|
||||
* entered.
|
||||
|
183
cmd/mii.c
183
cmd/mii.c
@ -12,25 +12,11 @@
|
||||
#include <command.h>
|
||||
#include <miiphy.h>
|
||||
|
||||
typedef struct _MII_reg_desc_t {
|
||||
ushort regno;
|
||||
char * name;
|
||||
} MII_reg_desc_t;
|
||||
|
||||
static const MII_reg_desc_t reg_0_5_desc_tbl[] = {
|
||||
{ MII_BMCR, "PHY control register" },
|
||||
{ MII_BMSR, "PHY status register" },
|
||||
{ MII_PHYSID1, "PHY ID 1 register" },
|
||||
{ MII_PHYSID2, "PHY ID 2 register" },
|
||||
{ MII_ADVERTISE, "Autonegotiation advertisement register" },
|
||||
{ MII_LPA, "Autonegotiation partner abilities register" },
|
||||
};
|
||||
|
||||
typedef struct _MII_field_desc_t {
|
||||
ushort hi;
|
||||
ushort lo;
|
||||
ushort mask;
|
||||
char * name;
|
||||
const char *name;
|
||||
} MII_field_desc_t;
|
||||
|
||||
static const MII_field_desc_t reg_0_desc_tbl[] = {
|
||||
@ -87,7 +73,7 @@ static const MII_field_desc_t reg_4_desc_tbl[] = {
|
||||
{ 7, 7, 0x01, "100BASE-TX able" },
|
||||
{ 6, 6, 0x01, "10BASE-T full duplex able" },
|
||||
{ 5, 5, 0x01, "10BASE-T able" },
|
||||
{ 4, 0, 0x1f, "xxx to do" },
|
||||
{ 4, 0, 0x1f, "selector" },
|
||||
};
|
||||
|
||||
static const MII_field_desc_t reg_5_desc_tbl[] = {
|
||||
@ -102,50 +88,91 @@ static const MII_field_desc_t reg_5_desc_tbl[] = {
|
||||
{ 7, 7, 0x01, "100BASE-TX able" },
|
||||
{ 6, 6, 0x01, "10BASE-T full duplex able" },
|
||||
{ 5, 5, 0x01, "10BASE-T able" },
|
||||
{ 4, 0, 0x1f, "xxx to do" },
|
||||
{ 4, 0, 0x1f, "partner selector" },
|
||||
};
|
||||
typedef struct _MII_field_desc_and_len_t {
|
||||
|
||||
static const MII_field_desc_t reg_9_desc_tbl[] = {
|
||||
{ 15, 13, 0x07, "test mode" },
|
||||
{ 12, 12, 0x01, "manual master/slave enable" },
|
||||
{ 11, 11, 0x01, "manual master/slave value" },
|
||||
{ 10, 10, 0x01, "multi/single port" },
|
||||
{ 9, 9, 0x01, "1000BASE-T full duplex able" },
|
||||
{ 8, 8, 0x01, "1000BASE-T half duplex able" },
|
||||
{ 7, 7, 0x01, "automatic TDR on link down" },
|
||||
{ 6, 6, 0x7f, "(reserved)" },
|
||||
};
|
||||
|
||||
static const MII_field_desc_t reg_10_desc_tbl[] = {
|
||||
{ 15, 15, 0x01, "master/slave config fault" },
|
||||
{ 14, 14, 0x01, "master/slave config result" },
|
||||
{ 13, 13, 0x01, "local receiver status OK" },
|
||||
{ 12, 12, 0x01, "remote receiver status OK" },
|
||||
{ 11, 11, 0x01, "1000BASE-T full duplex able" },
|
||||
{ 10, 10, 0x01, "1000BASE-T half duplex able" },
|
||||
{ 9, 8, 0x03, "(reserved)" },
|
||||
{ 7, 0, 0xff, "1000BASE-T idle error counter"},
|
||||
};
|
||||
|
||||
typedef struct _MII_reg_desc_t {
|
||||
ushort regno;
|
||||
const MII_field_desc_t *pdesc;
|
||||
ushort len;
|
||||
} MII_field_desc_and_len_t;
|
||||
const char *name;
|
||||
} MII_reg_desc_t;
|
||||
|
||||
static const MII_field_desc_and_len_t desc_and_len_tbl[] = {
|
||||
{ reg_0_desc_tbl, ARRAY_SIZE(reg_0_desc_tbl) },
|
||||
{ reg_1_desc_tbl, ARRAY_SIZE(reg_1_desc_tbl) },
|
||||
{ reg_2_desc_tbl, ARRAY_SIZE(reg_2_desc_tbl) },
|
||||
{ reg_3_desc_tbl, ARRAY_SIZE(reg_3_desc_tbl) },
|
||||
{ reg_4_desc_tbl, ARRAY_SIZE(reg_4_desc_tbl) },
|
||||
{ reg_5_desc_tbl, ARRAY_SIZE(reg_5_desc_tbl) },
|
||||
static const MII_reg_desc_t mii_reg_desc_tbl[] = {
|
||||
{ MII_BMCR, reg_0_desc_tbl, ARRAY_SIZE(reg_0_desc_tbl),
|
||||
"PHY control register" },
|
||||
{ MII_BMSR, reg_1_desc_tbl, ARRAY_SIZE(reg_1_desc_tbl),
|
||||
"PHY status register" },
|
||||
{ MII_PHYSID1, reg_2_desc_tbl, ARRAY_SIZE(reg_2_desc_tbl),
|
||||
"PHY ID 1 register" },
|
||||
{ MII_PHYSID2, reg_3_desc_tbl, ARRAY_SIZE(reg_3_desc_tbl),
|
||||
"PHY ID 2 register" },
|
||||
{ MII_ADVERTISE, reg_4_desc_tbl, ARRAY_SIZE(reg_4_desc_tbl),
|
||||
"Autonegotiation advertisement register" },
|
||||
{ MII_LPA, reg_5_desc_tbl, ARRAY_SIZE(reg_5_desc_tbl),
|
||||
"Autonegotiation partner abilities register" },
|
||||
{ MII_CTRL1000, reg_9_desc_tbl, ARRAY_SIZE(reg_9_desc_tbl),
|
||||
"1000BASE-T control register" },
|
||||
{ MII_STAT1000, reg_10_desc_tbl, ARRAY_SIZE(reg_10_desc_tbl),
|
||||
"1000BASE-T status register" },
|
||||
};
|
||||
|
||||
static void dump_reg(
|
||||
ushort regval,
|
||||
const MII_reg_desc_t *prd,
|
||||
const MII_field_desc_and_len_t *pdl);
|
||||
const MII_reg_desc_t *prd);
|
||||
|
||||
static int special_field(
|
||||
ushort regno,
|
||||
const MII_field_desc_t *pdesc,
|
||||
ushort regval);
|
||||
static bool special_field(ushort regno, const MII_field_desc_t *pdesc,
|
||||
ushort regval);
|
||||
|
||||
static void MII_dump_0_to_5(
|
||||
ushort regvals[6],
|
||||
uchar reglo,
|
||||
uchar reghi)
|
||||
static void MII_dump(const ushort *regvals, uchar reglo, uchar reghi)
|
||||
{
|
||||
ulong i;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
if ((reglo <= i) && (i <= reghi))
|
||||
dump_reg(regvals[i], ®_0_5_desc_tbl[i],
|
||||
&desc_and_len_tbl[i]);
|
||||
for (i = 0; i < ARRAY_SIZE(mii_reg_desc_tbl); i++) {
|
||||
const uchar reg = mii_reg_desc_tbl[i].regno;
|
||||
|
||||
if (reg >= reglo && reg <= reghi)
|
||||
dump_reg(regvals[reg - reglo], &mii_reg_desc_tbl[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print out field position, value, name */
|
||||
static void dump_field(const MII_field_desc_t *pdesc, ushort regval)
|
||||
{
|
||||
if (pdesc->hi == pdesc->lo)
|
||||
printf("%2u ", pdesc->lo);
|
||||
else
|
||||
printf("%2u-%2u", pdesc->hi, pdesc->lo);
|
||||
|
||||
printf(" = %5u %s", (regval >> pdesc->lo) & pdesc->mask,
|
||||
pdesc->name);
|
||||
}
|
||||
|
||||
static void dump_reg(
|
||||
ushort regval,
|
||||
const MII_reg_desc_t *prd,
|
||||
const MII_field_desc_and_len_t *pdl)
|
||||
const MII_reg_desc_t *prd)
|
||||
{
|
||||
ulong i;
|
||||
ushort mask_in_place;
|
||||
@ -154,8 +181,8 @@ static void dump_reg(
|
||||
printf("%u. (%04hx) -- %s --\n",
|
||||
prd->regno, regval, prd->name);
|
||||
|
||||
for (i = 0; i < pdl->len; i++) {
|
||||
pdesc = &pdl->pdesc[i];
|
||||
for (i = 0; i < prd->len; i++) {
|
||||
pdesc = &prd->pdesc[i];
|
||||
|
||||
mask_in_place = pdesc->mask << pdesc->lo;
|
||||
|
||||
@ -164,17 +191,8 @@ static void dump_reg(
|
||||
regval & mask_in_place,
|
||||
prd->regno);
|
||||
|
||||
if (special_field(prd->regno, pdesc, regval)) {
|
||||
}
|
||||
else {
|
||||
if (pdesc->hi == pdesc->lo)
|
||||
printf("%2u ", pdesc->lo);
|
||||
else
|
||||
printf("%2u-%2u", pdesc->hi, pdesc->lo);
|
||||
printf(" = %5u %s",
|
||||
(regval & mask_in_place) >> pdesc->lo,
|
||||
pdesc->name);
|
||||
}
|
||||
if (!special_field(prd->regno, pdesc, regval))
|
||||
dump_field(pdesc, regval);
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
@ -190,11 +208,11 @@ static void dump_reg(
|
||||
** 5.4-0
|
||||
*/
|
||||
|
||||
static int special_field(
|
||||
ushort regno,
|
||||
const MII_field_desc_t *pdesc,
|
||||
ushort regval)
|
||||
static bool special_field(ushort regno, const MII_field_desc_t *pdesc,
|
||||
ushort regval)
|
||||
{
|
||||
const ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
|
||||
|
||||
if ((regno == MII_BMCR) && (pdesc->lo == 6)) {
|
||||
ushort speed_bits = regval & (BMCR_SPEED1000 | BMCR_SPEED100);
|
||||
printf("%2u,%2u = b%u%u speed selection = %s Mbps",
|
||||
@ -208,34 +226,26 @@ static int special_field(
|
||||
}
|
||||
|
||||
else if ((regno == MII_BMCR) && (pdesc->lo == 8)) {
|
||||
printf("%2u = %5u duplex = %s",
|
||||
pdesc->lo,
|
||||
(regval >> pdesc->lo) & 1,
|
||||
((regval >> pdesc->lo) & 1) ? "full" : "half");
|
||||
dump_field(pdesc, regval);
|
||||
printf(" = %s", ((regval >> pdesc->lo) & 1) ? "full" : "half");
|
||||
return 1;
|
||||
}
|
||||
|
||||
else if ((regno == MII_ADVERTISE) && (pdesc->lo == 0)) {
|
||||
ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
|
||||
printf("%2u-%2u = %5u selector = %s",
|
||||
pdesc->hi, pdesc->lo, sel_bits,
|
||||
sel_bits == PHY_ANLPAR_PSB_802_3 ?
|
||||
"IEEE 802.3" :
|
||||
sel_bits == PHY_ANLPAR_PSB_802_9 ?
|
||||
"IEEE 802.9 ISLAN-16T" :
|
||||
"???");
|
||||
dump_field(pdesc, regval);
|
||||
printf(" = %s",
|
||||
sel_bits == PHY_ANLPAR_PSB_802_3 ? "IEEE 802.3 CSMA/CD" :
|
||||
sel_bits == PHY_ANLPAR_PSB_802_9 ?
|
||||
"IEEE 802.9 ISLAN-16T" : "???");
|
||||
return 1;
|
||||
}
|
||||
|
||||
else if ((regno == MII_LPA) && (pdesc->lo == 0)) {
|
||||
ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
|
||||
printf("%2u-%2u = %u selector = %s",
|
||||
pdesc->hi, pdesc->lo, sel_bits,
|
||||
sel_bits == PHY_ANLPAR_PSB_802_3 ?
|
||||
"IEEE 802.3" :
|
||||
sel_bits == PHY_ANLPAR_PSB_802_9 ?
|
||||
"IEEE 802.9 ISLAN-16T" :
|
||||
"???");
|
||||
dump_field(pdesc, regval);
|
||||
printf(" = %s",
|
||||
sel_bits == PHY_ANLPAR_PSB_802_3 ? "IEEE 802.3 CSMA/CD" :
|
||||
sel_bits == PHY_ANLPAR_PSB_802_9 ?
|
||||
"IEEE 802.9 ISLAN-16T" : "???");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -406,17 +416,16 @@ static int do_mii(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
}
|
||||
}
|
||||
} else if (strncmp(op, "du", 2) == 0) {
|
||||
ushort regs[6];
|
||||
ushort regs[MII_STAT1000 + 1]; /* Last reg is 0x0a */
|
||||
int ok = 1;
|
||||
if ((reglo > 5) || (reghi > 5)) {
|
||||
printf(
|
||||
"The MII dump command only formats the "
|
||||
"standard MII registers, 0-5.\n");
|
||||
if (reglo > MII_STAT1000 || reghi > MII_STAT1000) {
|
||||
printf("The MII dump command only formats the standard MII registers, 0-5, 9-a.\n");
|
||||
return 1;
|
||||
}
|
||||
for (addr = addrlo; addr <= addrhi; addr++) {
|
||||
for (reg = reglo; reg < reghi + 1; reg++) {
|
||||
if (miiphy_read(devname, addr, reg, ®s[reg]) != 0) {
|
||||
for (reg = reglo; reg <= reghi; reg++) {
|
||||
if (miiphy_read(devname, addr, reg,
|
||||
®s[reg - reglo]) != 0) {
|
||||
ok = 0;
|
||||
printf(
|
||||
"Error reading from the PHY addr=%02x reg=%02x\n",
|
||||
@ -425,7 +434,7 @@ static int do_mii(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
}
|
||||
}
|
||||
if (ok)
|
||||
MII_dump_0_to_5(regs, reglo, reghi);
|
||||
MII_dump(regs, reglo, reghi);
|
||||
printf("\n");
|
||||
}
|
||||
} else if (strncmp(op, "de", 2) == 0) {
|
||||
|
@ -44,6 +44,7 @@ CONFIG_SPL_MULTI_DTB_FIT_NO_COMPRESSION=y
|
||||
CONFIG_ENV_IS_IN_FAT=y
|
||||
CONFIG_ENV_FAT_INTERFACE="mmc"
|
||||
CONFIG_ENV_FAT_DEVICE_AND_PART="1:1"
|
||||
CONFIG_NET_RANDOM_ETHADDR=y
|
||||
CONFIG_DM=y
|
||||
CONFIG_SPL_DM=y
|
||||
CONFIG_SPL_DM_SEQ_ALIAS=y
|
||||
@ -58,6 +59,11 @@ CONFIG_K3_SEC_PROXY=y
|
||||
CONFIG_DM_MMC=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_K3_ARASAN=y
|
||||
CONFIG_PHY_TI=y
|
||||
CONFIG_PHY_FIXED=y
|
||||
CONFIG_DM_ETH=y
|
||||
CONFIG_TI_AM65_CPSW_NUSS=y
|
||||
CONFIG_PHY=y
|
||||
CONFIG_PINCTRL=y
|
||||
# CONFIG_PINCTRL_GENERIC is not set
|
||||
CONFIG_SPL_PINCTRL=y
|
||||
|
@ -11,6 +11,29 @@ config DM_ETH
|
||||
This is currently implemented in net/eth-uclass.c
|
||||
Look in include/net.h for details.
|
||||
|
||||
config DM_MDIO
|
||||
bool "Enable Driver Model for MDIO devices"
|
||||
depends on DM_ETH && PHYLIB
|
||||
help
|
||||
Enable driver model for MDIO devices
|
||||
|
||||
Adds UCLASS_MDIO DM class supporting MDIO buses that are probed as
|
||||
stand-alone devices. Useful in particular for systems that support
|
||||
DM_ETH and have a stand-alone MDIO hardware block shared by multiple
|
||||
Ethernet interfaces.
|
||||
This is currently implemented in net/mdio-uclass.c
|
||||
Look in include/miiphy.h for details.
|
||||
|
||||
config MDIO_SANDBOX
|
||||
depends on DM_MDIO && SANDBOX
|
||||
default y
|
||||
bool "Sandbox: Mocked MDIO driver"
|
||||
help
|
||||
This driver implements dummy read/write/reset MDIO functions mimicking
|
||||
a bus with a single PHY.
|
||||
|
||||
This driver is used in for testing in test/dm/mdio.c
|
||||
|
||||
menuconfig NETDEVICES
|
||||
bool "Network device support"
|
||||
depends on NET
|
||||
|
@ -77,3 +77,4 @@ obj-y += ti/
|
||||
obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
|
||||
obj-y += mscc_eswitch/
|
||||
obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o
|
||||
obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
|
||||
|
@ -613,10 +613,12 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
|
||||
|
||||
/* First check for GMAC and that it is GiB capable */
|
||||
if (gem_is_gigabit_capable(macb)) {
|
||||
lpa = macb_mdio_read(macb, MII_STAT1000);
|
||||
lpa = macb_mdio_read(macb, MII_LPA);
|
||||
|
||||
if (lpa & (LPA_1000FULL | LPA_1000HALF)) {
|
||||
duplex = ((lpa & LPA_1000FULL) ? 1 : 0);
|
||||
if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL |
|
||||
LPA_1000XHALF)) {
|
||||
duplex = ((lpa & (LPA_1000FULL | LPA_1000XFULL)) ?
|
||||
1 : 0);
|
||||
|
||||
printf("%s: link up, 1000Mbps %s-duplex (lpa: 0x%04x)\n",
|
||||
name,
|
||||
|
92
drivers/net/mdio_sandbox.c
Normal file
92
drivers/net/mdio_sandbox.c
Normal file
@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2019
|
||||
* Alex Marginean, NXP
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <miiphy.h>
|
||||
|
||||
#define SANDBOX_PHY_ADDR 5
|
||||
#define SANDBOX_PHY_REG 0
|
||||
|
||||
struct mdio_sandbox_priv {
|
||||
int enabled;
|
||||
u16 reg;
|
||||
};
|
||||
|
||||
static int mdio_sandbox_read(struct udevice *dev, int addr, int devad, int reg)
|
||||
{
|
||||
struct mdio_sandbox_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (!priv->enabled)
|
||||
return -ENODEV;
|
||||
|
||||
if (addr != SANDBOX_PHY_ADDR)
|
||||
return -ENODEV;
|
||||
if (devad != MDIO_DEVAD_NONE)
|
||||
return -ENODEV;
|
||||
if (reg != SANDBOX_PHY_REG)
|
||||
return -ENODEV;
|
||||
|
||||
return priv->reg;
|
||||
}
|
||||
|
||||
static int mdio_sandbox_write(struct udevice *dev, int addr, int devad, int reg,
|
||||
u16 val)
|
||||
{
|
||||
struct mdio_sandbox_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (!priv->enabled)
|
||||
return -ENODEV;
|
||||
|
||||
if (addr != SANDBOX_PHY_ADDR)
|
||||
return -ENODEV;
|
||||
if (devad != MDIO_DEVAD_NONE)
|
||||
return -ENODEV;
|
||||
if (reg != SANDBOX_PHY_REG)
|
||||
return -ENODEV;
|
||||
|
||||
priv->reg = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdio_sandbox_reset(struct udevice *dev)
|
||||
{
|
||||
struct mdio_sandbox_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->reg = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mdio_ops mdio_sandbox_ops = {
|
||||
.read = mdio_sandbox_read,
|
||||
.write = mdio_sandbox_write,
|
||||
.reset = mdio_sandbox_reset,
|
||||
};
|
||||
|
||||
static int mdio_sandbox_probe(struct udevice *dev)
|
||||
{
|
||||
struct mdio_sandbox_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id mdio_sandbox_ids[] = {
|
||||
{ .compatible = "sandbox,mdio" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(mdio_sandbox) = {
|
||||
.name = "mdio_sandbox",
|
||||
.id = UCLASS_MDIO,
|
||||
.of_match = mdio_sandbox_ids,
|
||||
.probe = mdio_sandbox_probe,
|
||||
.ops = &mdio_sandbox_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct mdio_sandbox_priv),
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
|
||||
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o
|
||||
obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o
|
||||
obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o
|
||||
obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o
|
||||
obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o
|
||||
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o mscc_miim.o
|
||||
obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o mscc_miim.o
|
||||
obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o mscc_miim.o
|
||||
obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o mscc_miim.o
|
||||
obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o mscc_miim.o
|
||||
|
@ -17,20 +17,7 @@
|
||||
|
||||
#include <dt-bindings/mscc/jr2_data.h>
|
||||
#include "mscc_xfer.h"
|
||||
|
||||
#define GCB_MIIM_MII_STATUS 0x0
|
||||
#define GCB_MIIM_STAT_BUSY BIT(3)
|
||||
#define GCB_MIIM_MII_CMD 0x8
|
||||
#define GCB_MIIM_MII_CMD_SCAN BIT(0)
|
||||
#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
|
||||
#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
|
||||
#define GCB_MIIM_MII_CMD_SINGLE_SCAN BIT(3)
|
||||
#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
|
||||
#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
|
||||
#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
|
||||
#define GCB_MIIM_MII_CMD_VLD BIT(31)
|
||||
#define GCB_MIIM_DATA 0xC
|
||||
#define GCB_MIIM_DATA_ERROR (0x3 << 16)
|
||||
#include "mscc_miim.h"
|
||||
|
||||
#define ANA_AC_RAM_CTRL_RAM_INIT 0x94358
|
||||
#define ANA_AC_STAT_GLOBAL_CFG_PORT_RESET 0x94370
|
||||
@ -279,13 +266,6 @@ struct jr2_private {
|
||||
struct jr2_phy_port_t ports[MAX_PORT];
|
||||
};
|
||||
|
||||
struct jr2_miim_dev {
|
||||
void __iomem *regs;
|
||||
phys_addr_t miim_base;
|
||||
unsigned long miim_size;
|
||||
struct mii_dev *bus;
|
||||
};
|
||||
|
||||
static const unsigned long jr2_regs_qs[] = {
|
||||
[MSCC_QS_XTR_RD] = 0x8,
|
||||
[MSCC_QS_XTR_FLUSH] = 0x18,
|
||||
@ -294,99 +274,9 @@ static const unsigned long jr2_regs_qs[] = {
|
||||
[MSCC_QS_INJ_CTRL] = 0x34,
|
||||
};
|
||||
|
||||
static struct jr2_miim_dev miim[JR2_MIIM_BUS_COUNT];
|
||||
static struct mscc_miim_dev miim[JR2_MIIM_BUS_COUNT];
|
||||
static int miim_count = -1;
|
||||
|
||||
static int mscc_miim_wait_ready(struct jr2_miim_dev *miim)
|
||||
{
|
||||
unsigned long deadline;
|
||||
u32 val;
|
||||
|
||||
deadline = timer_get_us() + 250000;
|
||||
|
||||
do {
|
||||
val = readl(miim->regs + GCB_MIIM_MII_STATUS);
|
||||
} while (timer_get_us() <= deadline && (val & GCB_MIIM_STAT_BUSY));
|
||||
|
||||
if (val & GCB_MIIM_STAT_BUSY)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
|
||||
{
|
||||
struct jr2_miim_dev *miim = (struct jr2_miim_dev *)bus->priv;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = mscc_miim_wait_ready(miim);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
|
||||
miim->regs + GCB_MIIM_MII_CMD);
|
||||
|
||||
ret = mscc_miim_wait_ready(miim);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
val = readl(miim->regs + GCB_MIIM_DATA);
|
||||
if (val & GCB_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 jr2_miim_dev *miim = (struct jr2_miim_dev *)bus->priv;
|
||||
int ret;
|
||||
|
||||
ret = mscc_miim_wait_ready(miim);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
|
||||
GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mii_dev *jr2_mdiobus_init(phys_addr_t miim_base,
|
||||
unsigned long miim_size)
|
||||
{
|
||||
struct mii_dev *bus;
|
||||
|
||||
bus = mdio_alloc();
|
||||
if (!bus)
|
||||
return NULL;
|
||||
|
||||
++miim_count;
|
||||
sprintf(bus->name, "miim-bus%d", miim_count);
|
||||
|
||||
miim[miim_count].regs = ioremap(miim_base, miim_size);
|
||||
miim[miim_count].miim_base = miim_base;
|
||||
miim[miim_count].miim_size = miim_size;
|
||||
bus->priv = &miim[miim_count];
|
||||
bus->read = mscc_miim_read;
|
||||
bus->write = mscc_miim_write;
|
||||
|
||||
if (mdio_register(bus))
|
||||
return NULL;
|
||||
|
||||
miim[miim_count].bus = bus;
|
||||
return bus;
|
||||
}
|
||||
|
||||
static void jr2_cpu_capture_setup(struct jr2_private *priv)
|
||||
{
|
||||
/* ASM: No preamble and IFH prefix on CPU injected frames */
|
||||
@ -973,7 +863,7 @@ static int jr2_probe(struct udevice *dev)
|
||||
}
|
||||
|
||||
/* Initialize miim buses */
|
||||
memset(&miim, 0x0, sizeof(struct jr2_miim_dev) * JR2_MIIM_BUS_COUNT);
|
||||
memset(&miim, 0x0, sizeof(struct mscc_miim_dev) * JR2_MIIM_BUS_COUNT);
|
||||
|
||||
/* iterate all the ports and find out on which bus they are */
|
||||
i = 0;
|
||||
@ -1008,7 +898,8 @@ static int jr2_probe(struct udevice *dev)
|
||||
/* If the bus is new then create a new bus */
|
||||
if (!get_mdiobus(addr_base, addr_size))
|
||||
priv->bus[miim_count] =
|
||||
jr2_mdiobus_init(addr_base, addr_size);
|
||||
mscc_mdiobus_init(miim, &miim_count, addr_base,
|
||||
addr_size);
|
||||
|
||||
/* Connect mdio bus with the port */
|
||||
bus = get_mdiobus(addr_base, addr_size);
|
||||
|
@ -17,18 +17,7 @@
|
||||
|
||||
#include "mscc_xfer.h"
|
||||
#include "mscc_mac_table.h"
|
||||
|
||||
#define GCB_MIIM_MII_STATUS 0x0
|
||||
#define GCB_MIIM_STAT_BUSY BIT(3)
|
||||
#define GCB_MIIM_MII_CMD 0x8
|
||||
#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
|
||||
#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
|
||||
#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
|
||||
#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
|
||||
#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
|
||||
#define GCB_MIIM_MII_CMD_VLD BIT(31)
|
||||
#define GCB_MIIM_DATA 0xC
|
||||
#define GCB_MIIM_DATA_ERROR (0x2 << 16)
|
||||
#include "mscc_miim.h"
|
||||
|
||||
#define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x))
|
||||
#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
|
||||
@ -189,13 +178,6 @@ struct luton_private {
|
||||
struct luton_phy_port_t ports[MAX_PORT];
|
||||
};
|
||||
|
||||
struct mscc_miim_dev {
|
||||
void __iomem *regs;
|
||||
phys_addr_t miim_base;
|
||||
unsigned long miim_size;
|
||||
struct mii_dev *bus;
|
||||
};
|
||||
|
||||
static const unsigned long luton_regs_qs[] = {
|
||||
[MSCC_QS_XTR_RD] = 0x18,
|
||||
[MSCC_QS_XTR_FLUSH] = 0x28,
|
||||
@ -213,84 +195,6 @@ static const unsigned long luton_regs_ana_table[] = {
|
||||
static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
|
||||
static int miim_count = -1;
|
||||
|
||||
static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
|
||||
{
|
||||
return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
|
||||
GCB_MIIM_STAT_BUSY, false, 250, false);
|
||||
}
|
||||
|
||||
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(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
|
||||
miim->regs + GCB_MIIM_MII_CMD);
|
||||
|
||||
ret = mscc_miim_wait_ready(miim);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
val = readl(miim->regs + GCB_MIIM_DATA);
|
||||
if (val & GCB_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(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
|
||||
GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base,
|
||||
unsigned long miim_size)
|
||||
{
|
||||
struct mii_dev *bus;
|
||||
|
||||
bus = mdio_alloc();
|
||||
if (!bus)
|
||||
return NULL;
|
||||
|
||||
++miim_count;
|
||||
sprintf(bus->name, "miim-bus%d", miim_count);
|
||||
|
||||
miim[miim_count].regs = ioremap(miim_base, miim_size);
|
||||
miim[miim_count].miim_base = miim_base;
|
||||
miim[miim_count].miim_size = miim_size;
|
||||
bus->priv = &miim[miim_count];
|
||||
bus->read = mscc_miim_read;
|
||||
bus->write = mscc_miim_write;
|
||||
|
||||
if (mdio_register(bus))
|
||||
return NULL;
|
||||
|
||||
miim[miim_count].bus = bus;
|
||||
return bus;
|
||||
}
|
||||
|
||||
static void luton_stop(struct udevice *dev)
|
||||
{
|
||||
struct luton_private *priv = dev_get_priv(dev);
|
||||
@ -760,7 +664,8 @@ static int luton_probe(struct udevice *dev)
|
||||
/* If the bus is new then create a new bus */
|
||||
if (!get_mdiobus(addr_base, addr_size))
|
||||
priv->bus[miim_count] =
|
||||
serval_mdiobus_init(addr_base, addr_size);
|
||||
mscc_mdiobus_init(miim, &miim_count, addr_base,
|
||||
addr_size);
|
||||
|
||||
/* Connect mdio bus with the port */
|
||||
bus = get_mdiobus(addr_base, addr_size);
|
||||
|
@ -72,3 +72,31 @@ int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct mii_dev *mscc_mdiobus_init(struct mscc_miim_dev *miim, int *miim_count,
|
||||
phys_addr_t miim_base,
|
||||
unsigned long miim_size)
|
||||
{
|
||||
struct mii_dev *bus;
|
||||
|
||||
bus = mdio_alloc();
|
||||
|
||||
if (!bus)
|
||||
return NULL;
|
||||
|
||||
*miim_count += 1;
|
||||
sprintf(bus->name, "miim-bus%d", *miim_count);
|
||||
|
||||
miim[*miim_count].regs = ioremap(miim_base, miim_size);
|
||||
miim[*miim_count].miim_base = miim_base;
|
||||
miim[*miim_count].miim_size = miim_size;
|
||||
bus->priv = &miim[*miim_count];
|
||||
bus->read = mscc_miim_read;
|
||||
bus->write = mscc_miim_write;
|
||||
|
||||
if (mdio_register(bus))
|
||||
return NULL;
|
||||
|
||||
miim[*miim_count].bus = bus;
|
||||
return bus;
|
||||
}
|
||||
|
@ -3,10 +3,22 @@
|
||||
* Copyright (c) 2018 Microsemi Corporation
|
||||
*/
|
||||
|
||||
#ifndef _MSCC_MIIM_H_
|
||||
#define _MSCC_MIIM_H_
|
||||
|
||||
struct mscc_miim_dev {
|
||||
void __iomem *regs;
|
||||
void __iomem *phy_regs;
|
||||
phys_addr_t miim_base;
|
||||
unsigned long miim_size;
|
||||
struct mii_dev *bus;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
struct mii_dev *mscc_mdiobus_init(struct mscc_miim_dev *miim, int *miim_count,
|
||||
phys_addr_t miim_base,
|
||||
unsigned long miim_size);
|
||||
|
||||
|
||||
#endif /* _MSCC_MIIM_H_ */
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "mscc_xfer.h"
|
||||
#include "mscc_mac_table.h"
|
||||
#include "mscc_miim.h"
|
||||
|
||||
#define PHY_CFG 0x0
|
||||
#define PHY_CFG_ENA 0xF
|
||||
@ -25,20 +26,6 @@
|
||||
#define PHY_STAT 0x4
|
||||
#define PHY_STAT_SUPERVISOR_COMPLETE BIT(0)
|
||||
|
||||
#define GCB_MIIM_MII_STATUS 0x0
|
||||
#define GCB_MIIM_STAT_BUSY BIT(3)
|
||||
#define GCB_MIIM_MII_CMD 0x8
|
||||
#define GCB_MIIM_MII_CMD_SCAN BIT(0)
|
||||
#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
|
||||
#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
|
||||
#define GCB_MIIM_MII_CMD_SINGLE_SCAN BIT(3)
|
||||
#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
|
||||
#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
|
||||
#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
|
||||
#define GCB_MIIM_MII_CMD_VLD BIT(31)
|
||||
#define GCB_MIIM_DATA 0xC
|
||||
#define GCB_MIIM_DATA_ERROR (0x3 << 16)
|
||||
|
||||
#define ANA_PORT_VLAN_CFG(x) (0x7000 + 0x100 * (x))
|
||||
#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
|
||||
#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
|
||||
@ -173,13 +160,6 @@ struct ocelot_private {
|
||||
struct ocelot_phy_port_t ports[MAX_PORT];
|
||||
};
|
||||
|
||||
struct mscc_miim_dev {
|
||||
void __iomem *regs;
|
||||
phys_addr_t miim_base;
|
||||
unsigned long miim_size;
|
||||
struct mii_dev *bus;
|
||||
};
|
||||
|
||||
static struct mscc_miim_dev miim[OCELOT_MIIM_BUS_COUNT];
|
||||
static int miim_count = -1;
|
||||
|
||||
@ -209,85 +189,6 @@ static void mscc_phy_reset(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
|
||||
{
|
||||
return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
|
||||
GCB_MIIM_STAT_BUSY, false, 250, false);
|
||||
}
|
||||
|
||||
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(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
|
||||
miim->regs + GCB_MIIM_MII_CMD);
|
||||
|
||||
ret = mscc_miim_wait_ready(miim);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
val = readl(miim->regs + GCB_MIIM_DATA);
|
||||
if (val & GCB_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(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
|
||||
GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mii_dev *ocelot_mdiobus_init(phys_addr_t miim_base,
|
||||
unsigned long miim_size)
|
||||
{
|
||||
struct mii_dev *bus;
|
||||
|
||||
bus = mdio_alloc();
|
||||
|
||||
if (!bus)
|
||||
return NULL;
|
||||
|
||||
++miim_count;
|
||||
sprintf(bus->name, "miim-bus%d", miim_count);
|
||||
|
||||
miim[miim_count].regs = ioremap(miim_base, miim_size);
|
||||
miim[miim_count].miim_base = miim_base;
|
||||
miim[miim_count].miim_size = miim_size;
|
||||
bus->priv = &miim[miim_count];
|
||||
bus->read = mscc_miim_read;
|
||||
bus->write = mscc_miim_write;
|
||||
|
||||
if (mdio_register(bus))
|
||||
return NULL;
|
||||
|
||||
miim[miim_count].bus = bus;
|
||||
return bus;
|
||||
}
|
||||
|
||||
__weak void mscc_switch_reset(void)
|
||||
{
|
||||
}
|
||||
@ -682,7 +583,8 @@ static int ocelot_probe(struct udevice *dev)
|
||||
/* If the bus is new then create a new bus */
|
||||
if (!get_mdiobus(addr_base, addr_size))
|
||||
priv->bus[miim_count] =
|
||||
ocelot_mdiobus_init(addr_base, addr_size);
|
||||
mscc_mdiobus_init(miim, &miim_count, addr_base,
|
||||
addr_size);
|
||||
|
||||
/* Connect mdio bus with the port */
|
||||
bus = get_mdiobus(addr_base, addr_size);
|
||||
|
@ -17,18 +17,7 @@
|
||||
|
||||
#include "mscc_xfer.h"
|
||||
#include "mscc_mac_table.h"
|
||||
|
||||
#define GCB_MIIM_MII_STATUS 0x0
|
||||
#define GCB_MIIM_STAT_BUSY BIT(3)
|
||||
#define GCB_MIIM_MII_CMD 0x8
|
||||
#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
|
||||
#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
|
||||
#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
|
||||
#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
|
||||
#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
|
||||
#define GCB_MIIM_MII_CMD_VLD BIT(31)
|
||||
#define GCB_MIIM_DATA 0xC
|
||||
#define GCB_MIIM_DATA_ERROR (0x2 << 16)
|
||||
#include "mscc_miim.h"
|
||||
|
||||
#define ANA_PORT_VLAN_CFG(x) (0xc000 + 0x100 * (x))
|
||||
#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
|
||||
@ -156,13 +145,6 @@ struct serval_private {
|
||||
struct serval_phy_port_t ports[MAX_PORT];
|
||||
};
|
||||
|
||||
struct mscc_miim_dev {
|
||||
void __iomem *regs;
|
||||
phys_addr_t miim_base;
|
||||
unsigned long miim_size;
|
||||
struct mii_dev *bus;
|
||||
};
|
||||
|
||||
static const unsigned long serval_regs_qs[] = {
|
||||
[MSCC_QS_XTR_RD] = 0x8,
|
||||
[MSCC_QS_XTR_FLUSH] = 0x18,
|
||||
@ -180,84 +162,6 @@ static const unsigned long serval_regs_ana_table[] = {
|
||||
static struct mscc_miim_dev miim[SERVAL_MIIM_BUS_COUNT];
|
||||
static int miim_count = -1;
|
||||
|
||||
static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
|
||||
{
|
||||
return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
|
||||
GCB_MIIM_STAT_BUSY, false, 250, false);
|
||||
}
|
||||
|
||||
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(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
|
||||
miim->regs + GCB_MIIM_MII_CMD);
|
||||
|
||||
ret = mscc_miim_wait_ready(miim);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
val = readl(miim->regs + GCB_MIIM_DATA);
|
||||
if (val & GCB_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(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
|
||||
GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base,
|
||||
unsigned long miim_size)
|
||||
{
|
||||
struct mii_dev *bus;
|
||||
|
||||
bus = mdio_alloc();
|
||||
if (!bus)
|
||||
return NULL;
|
||||
|
||||
++miim_count;
|
||||
sprintf(bus->name, "miim-bus%d", miim_count);
|
||||
|
||||
miim[miim_count].regs = ioremap(miim_base, miim_size);
|
||||
miim[miim_count].miim_base = miim_base;
|
||||
miim[miim_count].miim_size = miim_size;
|
||||
bus->priv = &miim[miim_count];
|
||||
bus->read = mscc_miim_read;
|
||||
bus->write = mscc_miim_write;
|
||||
|
||||
if (mdio_register(bus))
|
||||
return NULL;
|
||||
|
||||
miim[miim_count].bus = bus;
|
||||
return bus;
|
||||
}
|
||||
|
||||
static void serval_cpu_capture_setup(struct serval_private *priv)
|
||||
{
|
||||
int i;
|
||||
@ -356,8 +260,6 @@ static void serdes_write(void __iomem *base, u32 addr)
|
||||
do {
|
||||
data = readl(base + HSIO_MCB_SERDES1G_CFG);
|
||||
} while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
|
||||
|
||||
mdelay(100);
|
||||
}
|
||||
|
||||
static void serdes1g_setup(void __iomem *base, uint32_t addr,
|
||||
@ -636,7 +538,8 @@ static int serval_probe(struct udevice *dev)
|
||||
/* If the bus is new then create a new bus */
|
||||
if (!get_mdiobus(addr_base, addr_size))
|
||||
priv->bus[miim_count] =
|
||||
serval_mdiobus_init(addr_base, addr_size);
|
||||
mscc_mdiobus_init(miim, &miim_count, addr_base,
|
||||
addr_size);
|
||||
|
||||
/* Connect mdio bus with the port */
|
||||
bus = get_mdiobus(addr_base, addr_size);
|
||||
|
@ -16,18 +16,7 @@
|
||||
#include <wait_bit.h>
|
||||
|
||||
#include "mscc_xfer.h"
|
||||
|
||||
#define GCB_MIIM_MII_STATUS 0x0
|
||||
#define GCB_MIIM_STAT_BUSY BIT(3)
|
||||
#define GCB_MIIM_MII_CMD 0x8
|
||||
#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
|
||||
#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
|
||||
#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
|
||||
#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
|
||||
#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
|
||||
#define GCB_MIIM_MII_CMD_VLD BIT(31)
|
||||
#define GCB_MIIM_DATA 0xC
|
||||
#define GCB_MIIM_DATA_ERROR (0x3 << 16)
|
||||
#include "mscc_miim.h"
|
||||
|
||||
#define PHY_CFG 0x0
|
||||
#define PHY_CFG_ENA 0x3
|
||||
@ -134,13 +123,6 @@ struct servalt_private {
|
||||
struct servalt_phy_port_t ports[MAX_PORT];
|
||||
};
|
||||
|
||||
struct mscc_miim_dev {
|
||||
void __iomem *regs;
|
||||
phys_addr_t miim_base;
|
||||
unsigned long miim_size;
|
||||
struct mii_dev *bus;
|
||||
};
|
||||
|
||||
static const unsigned long servalt_regs_qs[] = {
|
||||
[MSCC_QS_XTR_RD] = 0x8,
|
||||
[MSCC_QS_XTR_FLUSH] = 0x18,
|
||||
@ -152,85 +134,6 @@ static const unsigned long servalt_regs_qs[] = {
|
||||
static struct mscc_miim_dev miim[SERVALT_MIIM_BUS_COUNT];
|
||||
static int miim_count = -1;
|
||||
|
||||
static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
|
||||
{
|
||||
return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
|
||||
GCB_MIIM_STAT_BUSY, false, 250, false);
|
||||
}
|
||||
|
||||
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(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
|
||||
miim->regs + GCB_MIIM_MII_CMD);
|
||||
|
||||
ret = mscc_miim_wait_ready(miim);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
val = readl(miim->regs + GCB_MIIM_DATA);
|
||||
if (val & GCB_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(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
|
||||
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
|
||||
GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mii_dev *servalt_mdiobus_init(phys_addr_t miim_base,
|
||||
unsigned long miim_size)
|
||||
{
|
||||
struct mii_dev *bus;
|
||||
|
||||
bus = mdio_alloc();
|
||||
if (!bus)
|
||||
return NULL;
|
||||
|
||||
++miim_count;
|
||||
sprintf(bus->name, "miim-bus%d", miim_count);
|
||||
|
||||
miim[miim_count].regs = ioremap(miim_base, miim_size);
|
||||
miim[miim_count].miim_base = miim_base;
|
||||
miim[miim_count].miim_size = miim_size;
|
||||
bus->priv = &miim[miim_count];
|
||||
bus->read = mscc_miim_read;
|
||||
bus->write = mscc_miim_write;
|
||||
|
||||
if (mdio_register(bus))
|
||||
return NULL;
|
||||
|
||||
miim[miim_count].bus = bus;
|
||||
return bus;
|
||||
}
|
||||
|
||||
static void mscc_phy_reset(void)
|
||||
{
|
||||
writel(0, BASE_DEVCPU_GCB + GCB_PHY_CFG + PHY_CFG);
|
||||
@ -564,7 +467,8 @@ static int servalt_probe(struct udevice *dev)
|
||||
/* If the bus is new then create a new bus */
|
||||
if (!get_mdiobus(addr_base, addr_size))
|
||||
priv->bus[miim_count] =
|
||||
servalt_mdiobus_init(addr_base, addr_size);
|
||||
mscc_mdiobus_init(miim, &miim_count, addr_base,
|
||||
addr_size);
|
||||
|
||||
/* Connect mdio bus with the port */
|
||||
bus = get_mdiobus(addr_base, addr_size);
|
||||
|
@ -176,8 +176,13 @@ void cs4340_upload_firmware(struct phy_device *phydev)
|
||||
printf("MMC read: dev # %u, block # %u, count %u ...\n",
|
||||
dev, blk, cnt);
|
||||
mmc_init(mmc);
|
||||
#ifdef CONFIG_BLK
|
||||
(void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
|
||||
addr);
|
||||
#else
|
||||
(void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt,
|
||||
addr);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -103,7 +103,7 @@ struct dp83867_private {
|
||||
int io_impedance;
|
||||
bool rxctrl_strap_quirk;
|
||||
int port_mirroring;
|
||||
int clk_output_sel;
|
||||
unsigned int clk_output_sel;
|
||||
};
|
||||
|
||||
static int dp83867_config_port_mirroring(struct phy_device *phydev)
|
||||
@ -136,17 +136,11 @@ static int dp83867_of_init(struct phy_device *phydev)
|
||||
ofnode node;
|
||||
u16 val;
|
||||
|
||||
/* Optional configuration */
|
||||
|
||||
node = phy_get_ofnode(phydev);
|
||||
if (!ofnode_valid(node))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Keep the default value if ti,clk-output-sel is not set
|
||||
* or to high
|
||||
*/
|
||||
|
||||
/* Keep the default value if ti,clk-output-sel is not set */
|
||||
dp83867->clk_output_sel =
|
||||
ofnode_read_u32_default(node, "ti,clk-output-sel",
|
||||
DP83867_CLK_O_SEL_REF_CLK);
|
||||
@ -162,14 +156,14 @@ static int dp83867_of_init(struct phy_device *phydev)
|
||||
dp83867->rxctrl_strap_quirk = true;
|
||||
dp83867->rx_id_delay = ofnode_read_u32_default(node,
|
||||
"ti,rx-internal-delay",
|
||||
-1);
|
||||
DEFAULT_RX_ID_DELAY);
|
||||
|
||||
dp83867->tx_id_delay = ofnode_read_u32_default(node,
|
||||
"ti,tx-internal-delay",
|
||||
-1);
|
||||
DEFAULT_TX_ID_DELAY);
|
||||
|
||||
dp83867->fifo_depth = ofnode_read_u32_default(node, "ti,fifo-depth",
|
||||
-1);
|
||||
DEFAULT_FIFO_DEPTH);
|
||||
if (ofnode_read_bool(node, "enet-phy-lane-swap"))
|
||||
dp83867->port_mirroring = DP83867_PORT_MIRRORING_EN;
|
||||
|
||||
|
@ -18,3 +18,11 @@ config DRIVER_TI_KEYSTONE_NET
|
||||
bool "TI Keystone 2 Ethernet"
|
||||
help
|
||||
This driver supports the TI Keystone 2 Ethernet subsystem
|
||||
|
||||
config TI_AM65_CPSW_NUSS
|
||||
bool "TI K3 AM65x MCU CPSW Nuss Ethernet controller driver"
|
||||
depends on ARCH_K3
|
||||
select PHYLIB
|
||||
help
|
||||
This driver supports TI K3 MCU CPSW Nuss Ethernet controller
|
||||
in Texas Instruments K3 AM65x SoCs.
|
||||
|
@ -5,3 +5,4 @@
|
||||
obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o cpsw_mdio.o
|
||||
obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
|
||||
obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o cpsw_mdio.o
|
||||
obj-$(CONFIG_TI_AM65_CPSW_NUSS) += am65-cpsw-nuss.o cpsw_mdio.o
|
||||
|
792
drivers/net/ti/am65-cpsw-nuss.c
Normal file
792
drivers/net/ti/am65-cpsw-nuss.c
Normal file
@ -0,0 +1,792 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver
|
||||
*
|
||||
* Copyright (C) 2019, Texas Instruments, Incorporated
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dma-uclass.h>
|
||||
#include <dm/of_access.h>
|
||||
#include <miiphy.h>
|
||||
#include <net.h>
|
||||
#include <phy.h>
|
||||
#include <power-domain.h>
|
||||
#include <linux/soc/ti/ti-udma.h>
|
||||
|
||||
#include "cpsw_mdio.h"
|
||||
|
||||
#define AM65_CPSW_CPSWNU_MAX_PORTS 2
|
||||
|
||||
#define AM65_CPSW_SS_BASE 0x0
|
||||
#define AM65_CPSW_SGMII_BASE 0x100
|
||||
#define AM65_CPSW_MDIO_BASE 0xf00
|
||||
#define AM65_CPSW_XGMII_BASE 0x2100
|
||||
#define AM65_CPSW_CPSW_NU_BASE 0x20000
|
||||
#define AM65_CPSW_CPSW_NU_ALE_BASE 0x1e000
|
||||
|
||||
#define AM65_CPSW_CPSW_NU_PORTS_OFFSET 0x1000
|
||||
#define AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET 0x330
|
||||
|
||||
#define AM65_CPSW_MDIO_BUS_FREQ_DEF 1000000
|
||||
|
||||
#define AM65_CPSW_CTL_REG 0x4
|
||||
#define AM65_CPSW_STAT_PORT_EN_REG 0x14
|
||||
#define AM65_CPSW_PTYPE_REG 0x18
|
||||
|
||||
#define AM65_CPSW_CTL_REG_P0_ENABLE BIT(2)
|
||||
#define AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE BIT(13)
|
||||
#define AM65_CPSW_CTL_REG_P0_RX_PAD BIT(14)
|
||||
|
||||
#define AM65_CPSW_P0_FLOW_ID_REG 0x8
|
||||
#define AM65_CPSW_PN_RX_MAXLEN_REG 0x24
|
||||
#define AM65_CPSW_PN_REG_SA_L 0x308
|
||||
#define AM65_CPSW_PN_REG_SA_H 0x30c
|
||||
|
||||
#define AM65_CPSW_ALE_CTL_REG 0x8
|
||||
#define AM65_CPSW_ALE_CTL_REG_ENABLE BIT(31)
|
||||
#define AM65_CPSW_ALE_CTL_REG_RESET_TBL BIT(30)
|
||||
#define AM65_CPSW_ALE_CTL_REG_BYPASS BIT(4)
|
||||
#define AM65_CPSW_ALE_PN_CTL_REG(x) (0x40 + (x) * 4)
|
||||
#define AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD 0x3
|
||||
#define AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY BIT(11)
|
||||
|
||||
#define AM65_CPSW_MACSL_CTL_REG 0x0
|
||||
#define AM65_CPSW_MACSL_CTL_REG_IFCTL_A BIT(15)
|
||||
#define AM65_CPSW_MACSL_CTL_REG_GIG BIT(7)
|
||||
#define AM65_CPSW_MACSL_CTL_REG_GMII_EN BIT(5)
|
||||
#define AM65_CPSW_MACSL_CTL_REG_LOOPBACK BIT(1)
|
||||
#define AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX BIT(0)
|
||||
#define AM65_CPSW_MACSL_RESET_REG 0x8
|
||||
#define AM65_CPSW_MACSL_RESET_REG_RESET BIT(0)
|
||||
#define AM65_CPSW_MACSL_STATUS_REG 0x4
|
||||
#define AM65_CPSW_MACSL_RESET_REG_PN_IDLE BIT(31)
|
||||
#define AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE BIT(30)
|
||||
#define AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE BIT(29)
|
||||
#define AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE BIT(28)
|
||||
#define AM65_CPSW_MACSL_RESET_REG_IDLE_MASK \
|
||||
(AM65_CPSW_MACSL_RESET_REG_PN_IDLE | \
|
||||
AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE | \
|
||||
AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE | \
|
||||
AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE)
|
||||
|
||||
#define AM65_CPSW_CPPI_PKT_TYPE 0x7
|
||||
|
||||
struct am65_cpsw_port {
|
||||
fdt_addr_t port_base;
|
||||
fdt_addr_t macsl_base;
|
||||
bool disabled;
|
||||
u32 mac_control;
|
||||
};
|
||||
|
||||
struct am65_cpsw_common {
|
||||
struct udevice *dev;
|
||||
fdt_addr_t ss_base;
|
||||
fdt_addr_t cpsw_base;
|
||||
fdt_addr_t mdio_base;
|
||||
fdt_addr_t ale_base;
|
||||
fdt_addr_t gmii_sel;
|
||||
fdt_addr_t mac_efuse;
|
||||
|
||||
struct clk fclk;
|
||||
struct power_domain pwrdmn;
|
||||
|
||||
u32 port_num;
|
||||
struct am65_cpsw_port ports[AM65_CPSW_CPSWNU_MAX_PORTS];
|
||||
u32 rflow_id_base;
|
||||
|
||||
struct mii_dev *bus;
|
||||
u32 bus_freq;
|
||||
|
||||
struct dma dma_tx;
|
||||
struct dma dma_rx;
|
||||
u32 rx_next;
|
||||
u32 rx_pend;
|
||||
bool started;
|
||||
};
|
||||
|
||||
struct am65_cpsw_priv {
|
||||
struct udevice *dev;
|
||||
struct am65_cpsw_common *cpsw_common;
|
||||
u32 port_id;
|
||||
|
||||
struct phy_device *phydev;
|
||||
bool has_phy;
|
||||
ofnode phy_node;
|
||||
u32 phy_addr;
|
||||
};
|
||||
|
||||
#ifdef PKTSIZE_ALIGN
|
||||
#define UDMA_RX_BUF_SIZE PKTSIZE_ALIGN
|
||||
#else
|
||||
#define UDMA_RX_BUF_SIZE ALIGN(1522, ARCH_DMA_MINALIGN)
|
||||
#endif
|
||||
|
||||
#ifdef PKTBUFSRX
|
||||
#define UDMA_RX_DESC_NUM PKTBUFSRX
|
||||
#else
|
||||
#define UDMA_RX_DESC_NUM 4
|
||||
#endif
|
||||
|
||||
#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \
|
||||
((mac)[2] << 16) | ((mac)[3] << 24))
|
||||
#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8))
|
||||
|
||||
static void am65_cpsw_set_sl_mac(struct am65_cpsw_port *slave,
|
||||
unsigned char *addr)
|
||||
{
|
||||
writel(mac_hi(addr),
|
||||
slave->port_base + AM65_CPSW_PN_REG_SA_H);
|
||||
writel(mac_lo(addr),
|
||||
slave->port_base + AM65_CPSW_PN_REG_SA_L);
|
||||
}
|
||||
|
||||
int am65_cpsw_macsl_reset(struct am65_cpsw_port *slave)
|
||||
{
|
||||
u32 i = 100;
|
||||
|
||||
/* Set the soft reset bit */
|
||||
writel(AM65_CPSW_MACSL_RESET_REG_RESET,
|
||||
slave->macsl_base + AM65_CPSW_MACSL_RESET_REG);
|
||||
|
||||
while ((readl(slave->macsl_base + AM65_CPSW_MACSL_RESET_REG) &
|
||||
AM65_CPSW_MACSL_RESET_REG_RESET) && i--)
|
||||
cpu_relax();
|
||||
|
||||
/* Timeout on the reset */
|
||||
return i;
|
||||
}
|
||||
|
||||
static int am65_cpsw_macsl_wait_for_idle(struct am65_cpsw_port *slave)
|
||||
{
|
||||
u32 i = 100;
|
||||
|
||||
while ((readl(slave->macsl_base + AM65_CPSW_MACSL_STATUS_REG) &
|
||||
AM65_CPSW_MACSL_RESET_REG_IDLE_MASK) && i--)
|
||||
cpu_relax();
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int am65_cpsw_update_link(struct am65_cpsw_priv *priv)
|
||||
{
|
||||
struct am65_cpsw_common *common = priv->cpsw_common;
|
||||
struct am65_cpsw_port *port = &common->ports[priv->port_id];
|
||||
struct phy_device *phy = priv->phydev;
|
||||
u32 mac_control = 0;
|
||||
|
||||
if (phy->link) { /* link up */
|
||||
mac_control = /*AM65_CPSW_MACSL_CTL_REG_LOOPBACK |*/
|
||||
AM65_CPSW_MACSL_CTL_REG_GMII_EN;
|
||||
if (phy->speed == 1000)
|
||||
mac_control |= AM65_CPSW_MACSL_CTL_REG_GIG;
|
||||
if (phy->duplex == DUPLEX_FULL)
|
||||
mac_control |= AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX;
|
||||
if (phy->speed == 100)
|
||||
mac_control |= AM65_CPSW_MACSL_CTL_REG_IFCTL_A;
|
||||
}
|
||||
|
||||
if (mac_control == port->mac_control)
|
||||
goto out;
|
||||
|
||||
if (mac_control) {
|
||||
printf("link up on port %d, speed %d, %s duplex\n",
|
||||
priv->port_id, phy->speed,
|
||||
(phy->duplex == DUPLEX_FULL) ? "full" : "half");
|
||||
} else {
|
||||
printf("link down on port %d\n", priv->port_id);
|
||||
}
|
||||
|
||||
writel(mac_control, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
|
||||
port->mac_control = mac_control;
|
||||
|
||||
out:
|
||||
return phy->link;
|
||||
}
|
||||
|
||||
#define AM65_GMII_SEL_MODE_MII 0
|
||||
#define AM65_GMII_SEL_MODE_RMII 1
|
||||
#define AM65_GMII_SEL_MODE_RGMII 2
|
||||
|
||||
#define AM65_GMII_SEL_RGMII_IDMODE BIT(4)
|
||||
|
||||
static void am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv,
|
||||
phy_interface_t phy_mode, int slave)
|
||||
{
|
||||
struct am65_cpsw_common *common = priv->cpsw_common;
|
||||
u32 reg;
|
||||
u32 mode = 0;
|
||||
bool rgmii_id = false;
|
||||
|
||||
reg = readl(common->gmii_sel);
|
||||
|
||||
dev_dbg(common->dev, "old gmii_sel: %08x\n", reg);
|
||||
|
||||
switch (phy_mode) {
|
||||
case PHY_INTERFACE_MODE_RMII:
|
||||
mode = AM65_GMII_SEL_MODE_RMII;
|
||||
break;
|
||||
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
mode = AM65_GMII_SEL_MODE_RGMII;
|
||||
break;
|
||||
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
mode = AM65_GMII_SEL_MODE_RGMII;
|
||||
rgmii_id = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(common->dev,
|
||||
"Unsupported PHY mode: %u. Defaulting to MII.\n",
|
||||
phy_mode);
|
||||
/* fallthrough */
|
||||
case PHY_INTERFACE_MODE_MII:
|
||||
mode = AM65_GMII_SEL_MODE_MII;
|
||||
break;
|
||||
};
|
||||
|
||||
if (rgmii_id)
|
||||
mode |= AM65_GMII_SEL_RGMII_IDMODE;
|
||||
|
||||
reg = mode;
|
||||
dev_dbg(common->dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n",
|
||||
phy_mode, reg);
|
||||
writel(reg, common->gmii_sel);
|
||||
|
||||
reg = readl(common->gmii_sel);
|
||||
if (reg != mode)
|
||||
dev_err(common->dev,
|
||||
"gmii_sel PHY mode NOT SET!: requested: %08x, gmii_sel: %08x\n",
|
||||
mode, reg);
|
||||
}
|
||||
|
||||
static int am65_cpsw_start(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct am65_cpsw_common *common = priv->cpsw_common;
|
||||
struct am65_cpsw_port *port = &common->ports[priv->port_id];
|
||||
struct am65_cpsw_port *port0 = &common->ports[0];
|
||||
int ret, i;
|
||||
|
||||
ret = power_domain_on(&common->pwrdmn);
|
||||
if (ret) {
|
||||
dev_err(dev, "power_domain_on() failed %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = clk_enable(&common->fclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "clk enabled failed %d\n", ret);
|
||||
goto err_off_pwrdm;
|
||||
}
|
||||
|
||||
common->rx_next = 0;
|
||||
common->rx_pend = 0;
|
||||
ret = dma_get_by_name(common->dev, "tx0", &common->dma_tx);
|
||||
if (ret) {
|
||||
dev_err(dev, "TX dma get failed %d\n", ret);
|
||||
goto err_off_clk;
|
||||
}
|
||||
ret = dma_get_by_name(common->dev, "rx", &common->dma_rx);
|
||||
if (ret) {
|
||||
dev_err(dev, "RX dma get failed %d\n", ret);
|
||||
goto err_free_tx;
|
||||
}
|
||||
|
||||
for (i = 0; i < UDMA_RX_DESC_NUM; i++) {
|
||||
ret = dma_prepare_rcv_buf(&common->dma_rx,
|
||||
net_rx_packets[i],
|
||||
UDMA_RX_BUF_SIZE);
|
||||
if (ret) {
|
||||
dev_err(dev, "RX dma add buf failed %d\n", ret);
|
||||
goto err_free_tx;
|
||||
}
|
||||
}
|
||||
|
||||
ret = dma_enable(&common->dma_tx);
|
||||
if (ret) {
|
||||
dev_err(dev, "TX dma_enable failed %d\n", ret);
|
||||
goto err_free_rx;
|
||||
}
|
||||
ret = dma_enable(&common->dma_rx);
|
||||
if (ret) {
|
||||
dev_err(dev, "RX dma_enable failed %d\n", ret);
|
||||
goto err_dis_tx;
|
||||
}
|
||||
|
||||
/* Control register */
|
||||
writel(AM65_CPSW_CTL_REG_P0_ENABLE |
|
||||
AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE |
|
||||
AM65_CPSW_CTL_REG_P0_RX_PAD,
|
||||
common->cpsw_base + AM65_CPSW_CTL_REG);
|
||||
|
||||
/* disable priority elevation */
|
||||
writel(0, common->cpsw_base + AM65_CPSW_PTYPE_REG);
|
||||
|
||||
/* enable statistics */
|
||||
writel(BIT(0) | BIT(priv->port_id),
|
||||
common->cpsw_base + AM65_CPSW_STAT_PORT_EN_REG);
|
||||
|
||||
/* Port 0 length register */
|
||||
writel(PKTSIZE_ALIGN, port0->port_base + AM65_CPSW_PN_RX_MAXLEN_REG);
|
||||
|
||||
/* set base flow_id */
|
||||
writel(common->rflow_id_base,
|
||||
port0->port_base + AM65_CPSW_P0_FLOW_ID_REG);
|
||||
|
||||
/* Reset and enable the ALE */
|
||||
writel(AM65_CPSW_ALE_CTL_REG_ENABLE | AM65_CPSW_ALE_CTL_REG_RESET_TBL |
|
||||
AM65_CPSW_ALE_CTL_REG_BYPASS,
|
||||
common->ale_base + AM65_CPSW_ALE_CTL_REG);
|
||||
|
||||
/* port 0 put into forward mode */
|
||||
writel(AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD,
|
||||
common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
|
||||
|
||||
/* PORT x configuration */
|
||||
|
||||
/* Port x Max length register */
|
||||
writel(PKTSIZE_ALIGN, port->port_base + AM65_CPSW_PN_RX_MAXLEN_REG);
|
||||
|
||||
/* Port x set mac */
|
||||
am65_cpsw_set_sl_mac(port, pdata->enetaddr);
|
||||
|
||||
/* Port x ALE: mac_only, Forwarding */
|
||||
writel(AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY |
|
||||
AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD,
|
||||
common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
|
||||
|
||||
port->mac_control = 0;
|
||||
if (!am65_cpsw_macsl_reset(port)) {
|
||||
dev_err(dev, "mac_sl reset failed\n");
|
||||
ret = -EFAULT;
|
||||
goto err_dis_rx;
|
||||
}
|
||||
|
||||
ret = phy_startup(priv->phydev);
|
||||
if (ret) {
|
||||
dev_err(dev, "phy_startup failed\n");
|
||||
goto err_dis_rx;
|
||||
}
|
||||
|
||||
ret = am65_cpsw_update_link(priv);
|
||||
if (!ret) {
|
||||
ret = -ENODEV;
|
||||
goto err_phy_shutdown;
|
||||
}
|
||||
|
||||
common->started = true;
|
||||
|
||||
return 0;
|
||||
|
||||
err_phy_shutdown:
|
||||
phy_shutdown(priv->phydev);
|
||||
err_dis_rx:
|
||||
/* disable ports */
|
||||
writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
|
||||
writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
|
||||
if (!am65_cpsw_macsl_wait_for_idle(port))
|
||||
dev_err(dev, "mac_sl idle timeout\n");
|
||||
writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
|
||||
writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG);
|
||||
writel(0, common->cpsw_base + AM65_CPSW_CTL_REG);
|
||||
|
||||
dma_disable(&common->dma_rx);
|
||||
err_dis_tx:
|
||||
dma_disable(&common->dma_tx);
|
||||
err_free_rx:
|
||||
dma_free(&common->dma_rx);
|
||||
err_free_tx:
|
||||
dma_free(&common->dma_tx);
|
||||
err_off_clk:
|
||||
clk_disable(&common->fclk);
|
||||
err_off_pwrdm:
|
||||
power_domain_off(&common->pwrdmn);
|
||||
out:
|
||||
dev_err(dev, "%s end error\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int am65_cpsw_send(struct udevice *dev, void *packet, int length)
|
||||
{
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct am65_cpsw_common *common = priv->cpsw_common;
|
||||
struct ti_udma_drv_packet_data packet_data;
|
||||
int ret;
|
||||
|
||||
packet_data.pkt_type = AM65_CPSW_CPPI_PKT_TYPE;
|
||||
packet_data.dest_tag = priv->port_id;
|
||||
ret = dma_send(&common->dma_tx, packet, length, &packet_data);
|
||||
if (ret) {
|
||||
dev_err(dev, "TX dma_send failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am65_cpsw_recv(struct udevice *dev, int flags, uchar **packetp)
|
||||
{
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct am65_cpsw_common *common = priv->cpsw_common;
|
||||
|
||||
/* try to receive a new packet */
|
||||
return dma_receive(&common->dma_rx, (void **)packetp, NULL);
|
||||
}
|
||||
|
||||
static int am65_cpsw_free_pkt(struct udevice *dev, uchar *packet, int length)
|
||||
{
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct am65_cpsw_common *common = priv->cpsw_common;
|
||||
int ret;
|
||||
|
||||
if (length > 0) {
|
||||
u32 pkt = common->rx_next % UDMA_RX_DESC_NUM;
|
||||
|
||||
ret = dma_prepare_rcv_buf(&common->dma_rx,
|
||||
net_rx_packets[pkt],
|
||||
UDMA_RX_BUF_SIZE);
|
||||
if (ret)
|
||||
dev_err(dev, "RX dma free_pkt failed %d\n", ret);
|
||||
common->rx_next++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void am65_cpsw_stop(struct udevice *dev)
|
||||
{
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct am65_cpsw_common *common = priv->cpsw_common;
|
||||
struct am65_cpsw_port *port = &common->ports[priv->port_id];
|
||||
|
||||
if (!common->started)
|
||||
return;
|
||||
|
||||
phy_shutdown(priv->phydev);
|
||||
|
||||
writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
|
||||
writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
|
||||
if (!am65_cpsw_macsl_wait_for_idle(port))
|
||||
dev_err(dev, "mac_sl idle timeout\n");
|
||||
writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
|
||||
writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG);
|
||||
writel(0, common->cpsw_base + AM65_CPSW_CTL_REG);
|
||||
|
||||
dma_disable(&common->dma_tx);
|
||||
dma_free(&common->dma_tx);
|
||||
|
||||
dma_disable(&common->dma_rx);
|
||||
dma_free(&common->dma_rx);
|
||||
|
||||
common->started = false;
|
||||
}
|
||||
|
||||
static int am65_cpsw_read_rom_hwaddr(struct udevice *dev)
|
||||
{
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct am65_cpsw_common *common = priv->cpsw_common;
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
u32 mac_hi, mac_lo;
|
||||
|
||||
if (common->mac_efuse == FDT_ADDR_T_NONE)
|
||||
return -1;
|
||||
|
||||
mac_lo = readl(common->mac_efuse);
|
||||
mac_hi = readl(common->mac_efuse + 4);
|
||||
pdata->enetaddr[0] = (mac_hi >> 8) & 0xff;
|
||||
pdata->enetaddr[1] = mac_hi & 0xff;
|
||||
pdata->enetaddr[2] = (mac_lo >> 24) & 0xff;
|
||||
pdata->enetaddr[3] = (mac_lo >> 16) & 0xff;
|
||||
pdata->enetaddr[4] = (mac_lo >> 8) & 0xff;
|
||||
pdata->enetaddr[5] = mac_lo & 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct eth_ops am65_cpsw_ops = {
|
||||
.start = am65_cpsw_start,
|
||||
.send = am65_cpsw_send,
|
||||
.recv = am65_cpsw_recv,
|
||||
.free_pkt = am65_cpsw_free_pkt,
|
||||
.stop = am65_cpsw_stop,
|
||||
.read_rom_hwaddr = am65_cpsw_read_rom_hwaddr,
|
||||
};
|
||||
|
||||
static int am65_cpsw_mdio_init(struct udevice *dev)
|
||||
{
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct am65_cpsw_common *cpsw_common = priv->cpsw_common;
|
||||
|
||||
if (!priv->has_phy || cpsw_common->bus)
|
||||
return 0;
|
||||
|
||||
cpsw_common->bus = cpsw_mdio_init(dev->name,
|
||||
cpsw_common->mdio_base,
|
||||
cpsw_common->bus_freq,
|
||||
clk_get_rate(&cpsw_common->fclk));
|
||||
if (!cpsw_common->bus)
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am65_cpsw_phy_init(struct udevice *dev)
|
||||
{
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct am65_cpsw_common *cpsw_common = priv->cpsw_common;
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct phy_device *phydev;
|
||||
u32 supported = PHY_GBIT_FEATURES;
|
||||
int ret;
|
||||
|
||||
phydev = phy_connect(cpsw_common->bus,
|
||||
priv->phy_addr,
|
||||
priv->dev,
|
||||
pdata->phy_interface);
|
||||
|
||||
if (!phydev) {
|
||||
dev_err(dev, "phy_connect() failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phydev->supported &= supported;
|
||||
if (pdata->max_speed) {
|
||||
ret = phy_set_supported(phydev, pdata->max_speed);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
phydev->advertising = phydev->supported;
|
||||
|
||||
if (ofnode_valid(priv->phy_node))
|
||||
phydev->node = priv->phy_node;
|
||||
|
||||
priv->phydev = phydev;
|
||||
ret = phy_config(phydev);
|
||||
if (ret < 0)
|
||||
pr_err("phy_config() failed: %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int am65_cpsw_ofdata_parse_phy(struct udevice *dev, ofnode port_np)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct ofnode_phandle_args out_args;
|
||||
const char *phy_mode;
|
||||
int ret = 0;
|
||||
|
||||
phy_mode = ofnode_read_string(port_np, "phy-mode");
|
||||
if (phy_mode) {
|
||||
pdata->phy_interface =
|
||||
phy_get_interface_by_name(phy_mode);
|
||||
if (pdata->phy_interface == -1) {
|
||||
dev_err(dev, "Invalid PHY mode '%s', port %u\n",
|
||||
phy_mode, priv->port_id);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ofnode_read_u32(port_np, "max-speed", (u32 *)&pdata->max_speed);
|
||||
if (pdata->max_speed)
|
||||
dev_err(dev, "Port %u speed froced to %uMbit\n",
|
||||
priv->port_id, pdata->max_speed);
|
||||
|
||||
priv->has_phy = true;
|
||||
ret = ofnode_parse_phandle_with_args(port_np, "phy-handle",
|
||||
NULL, 0, 0, &out_args);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't parse phy-handle port %u (%d)\n",
|
||||
priv->port_id, ret);
|
||||
priv->has_phy = false;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
priv->phy_node = out_args.node;
|
||||
if (priv->has_phy) {
|
||||
ret = ofnode_read_u32(priv->phy_node, "reg", &priv->phy_addr);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get phy_addr port %u (%d)\n",
|
||||
priv->port_id, ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int am65_cpsw_probe_cpsw(struct udevice *dev)
|
||||
{
|
||||
struct am65_cpsw_priv *priv = dev_get_priv(dev);
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct am65_cpsw_common *cpsw_common;
|
||||
ofnode ports_np, node;
|
||||
int ret, i;
|
||||
|
||||
priv->dev = dev;
|
||||
|
||||
cpsw_common = calloc(1, sizeof(*priv->cpsw_common));
|
||||
if (!cpsw_common)
|
||||
return -ENOMEM;
|
||||
priv->cpsw_common = cpsw_common;
|
||||
|
||||
cpsw_common->dev = dev;
|
||||
cpsw_common->ss_base = dev_read_addr(dev);
|
||||
if (cpsw_common->ss_base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
cpsw_common->mac_efuse = devfdt_get_addr_name(dev, "mac_efuse");
|
||||
/* no err check - optional */
|
||||
|
||||
ret = power_domain_get_by_index(dev, &cpsw_common->pwrdmn, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get pwrdmn: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_get_by_name(dev, "fck", &cpsw_common->fclk);
|
||||
if (ret) {
|
||||
power_domain_free(&cpsw_common->pwrdmn);
|
||||
dev_err(dev, "failed to get clock %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cpsw_common->cpsw_base = cpsw_common->ss_base + AM65_CPSW_CPSW_NU_BASE;
|
||||
cpsw_common->ale_base = cpsw_common->cpsw_base +
|
||||
AM65_CPSW_CPSW_NU_ALE_BASE;
|
||||
cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE;
|
||||
|
||||
cpsw_common->rflow_id_base = 0;
|
||||
cpsw_common->rflow_id_base =
|
||||
dev_read_u32_default(dev, "ti,rx-flow-id-base",
|
||||
cpsw_common->rflow_id_base);
|
||||
|
||||
ports_np = dev_read_subnode(dev, "ports");
|
||||
if (!ofnode_valid(ports_np)) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ofnode_for_each_subnode(node, ports_np) {
|
||||
const char *node_name;
|
||||
u32 port_id;
|
||||
bool disabled;
|
||||
|
||||
node_name = ofnode_get_name(node);
|
||||
|
||||
disabled = !ofnode_is_available(node);
|
||||
|
||||
ret = ofnode_read_u32(node, "reg", &port_id);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: failed to get port_id (%d)\n",
|
||||
node_name, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (port_id >= AM65_CPSW_CPSWNU_MAX_PORTS) {
|
||||
dev_err(dev, "%s: invalid port_id (%d)\n",
|
||||
node_name, port_id);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
cpsw_common->port_num++;
|
||||
|
||||
if (!port_id)
|
||||
continue;
|
||||
|
||||
priv->port_id = port_id;
|
||||
cpsw_common->ports[port_id].disabled = disabled;
|
||||
if (disabled)
|
||||
continue;
|
||||
|
||||
ret = am65_cpsw_ofdata_parse_phy(dev, node);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < AM65_CPSW_CPSWNU_MAX_PORTS; i++) {
|
||||
struct am65_cpsw_port *port = &cpsw_common->ports[i];
|
||||
|
||||
port->port_base = cpsw_common->cpsw_base +
|
||||
AM65_CPSW_CPSW_NU_PORTS_OFFSET +
|
||||
(i * AM65_CPSW_CPSW_NU_PORTS_OFFSET);
|
||||
port->macsl_base = port->port_base +
|
||||
AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET;
|
||||
}
|
||||
|
||||
node = dev_read_subnode(dev, "cpsw-phy-sel");
|
||||
if (!ofnode_valid(node)) {
|
||||
dev_err(dev, "can't find cpsw-phy-sel\n");
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cpsw_common->gmii_sel = ofnode_get_addr(node);
|
||||
if (cpsw_common->gmii_sel == FDT_ADDR_T_NONE) {
|
||||
dev_err(dev, "failed to get gmii_sel base\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
node = dev_read_subnode(dev, "mdio");
|
||||
if (!ofnode_valid(node)) {
|
||||
dev_err(dev, "can't find mdio\n");
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cpsw_common->bus_freq =
|
||||
dev_read_u32_default(dev, "bus_freq",
|
||||
AM65_CPSW_MDIO_BUS_FREQ_DEF);
|
||||
|
||||
am65_cpsw_gmii_sel_k3(priv, pdata->phy_interface, priv->port_id);
|
||||
|
||||
ret = am65_cpsw_mdio_init(dev);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = am65_cpsw_phy_init(dev);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u rflow_id_base:%u mdio_freq:%u\n",
|
||||
readl(cpsw_common->ss_base),
|
||||
readl(cpsw_common->cpsw_base),
|
||||
readl(cpsw_common->ale_base),
|
||||
cpsw_common->port_num,
|
||||
cpsw_common->rflow_id_base,
|
||||
cpsw_common->bus_freq);
|
||||
|
||||
out:
|
||||
clk_free(&cpsw_common->fclk);
|
||||
power_domain_free(&cpsw_common->pwrdmn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct udevice_id am65_cpsw_nuss_ids[] = {
|
||||
{ .compatible = "ti,am654-cpsw-nuss" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(am65_cpsw_nuss_slave) = {
|
||||
.name = "am65_cpsw_nuss_slave",
|
||||
.id = UCLASS_ETH,
|
||||
.of_match = am65_cpsw_nuss_ids,
|
||||
.probe = am65_cpsw_probe_cpsw,
|
||||
.ops = &am65_cpsw_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct am65_cpsw_priv),
|
||||
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
|
||||
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
||||
};
|
@ -125,7 +125,7 @@ u32 cpsw_mdio_get_alive(struct mii_dev *bus)
|
||||
return val & GENMASK(15, 0);
|
||||
}
|
||||
|
||||
struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base,
|
||||
struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base,
|
||||
u32 bus_freq, int fck_freq)
|
||||
{
|
||||
struct cpsw_mdio *cpsw_mdio;
|
||||
@ -144,7 +144,7 @@ struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cpsw_mdio->regs = (struct cpsw_mdio_regs *)mdio_base;
|
||||
cpsw_mdio->regs = (struct cpsw_mdio_regs *)(uintptr_t)mdio_base;
|
||||
|
||||
if (!bus_freq || !fck_freq)
|
||||
cpsw_mdio->div = CPSW_MDIO_DIV_DEF;
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
struct cpsw_mdio;
|
||||
|
||||
struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base,
|
||||
struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base,
|
||||
u32 bus_freq, int fck_freq);
|
||||
void cpsw_mdio_free(struct mii_dev *bus);
|
||||
u32 cpsw_mdio_get_alive(struct mii_dev *bus);
|
||||
|
@ -58,6 +58,7 @@ enum uclass_id {
|
||||
UCLASS_LPC, /* x86 'low pin count' interface */
|
||||
UCLASS_MAILBOX, /* Mailbox controller */
|
||||
UCLASS_MASS_STORAGE, /* Mass storage device */
|
||||
UCLASS_MDIO, /* MDIO bus */
|
||||
UCLASS_MISC, /* Miscellaneous device */
|
||||
UCLASS_MMC, /* SD / MMC card or chip */
|
||||
UCLASS_MOD_EXP, /* RSA Mod Exp device */
|
||||
|
@ -118,4 +118,53 @@ int bb_miiphy_write(struct mii_dev *miidev, int addr, int devad, int reg,
|
||||
#define ESTATUS_1000XF 0x8000
|
||||
#define ESTATUS_1000XH 0x4000
|
||||
|
||||
#ifdef CONFIG_DM_MDIO
|
||||
|
||||
/**
|
||||
* struct mdio_perdev_priv - Per-device class data for MDIO DM
|
||||
*
|
||||
* @mii_bus: Supporting MII legacy bus
|
||||
*/
|
||||
struct mdio_perdev_priv {
|
||||
struct mii_dev *mii_bus;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mdio_ops - MDIO bus operations
|
||||
*
|
||||
* @read: Read from a PHY register
|
||||
* @write: Write to a PHY register
|
||||
* @reset: Reset the MDIO bus, NULL if not supported
|
||||
*/
|
||||
struct mdio_ops {
|
||||
int (*read)(struct udevice *mdio_dev, int addr, int devad, int reg);
|
||||
int (*write)(struct udevice *mdio_dev, int addr, int devad, int reg,
|
||||
u16 val);
|
||||
int (*reset)(struct udevice *mdio_dev);
|
||||
};
|
||||
|
||||
#define mdio_get_ops(dev) ((struct mdio_ops *)(dev)->driver->ops)
|
||||
|
||||
/**
|
||||
* dm_mdio_probe_devices - Call probe on all MII devices, currently used for
|
||||
* MDIO console commands.
|
||||
*/
|
||||
void dm_mdio_probe_devices(void);
|
||||
|
||||
/**
|
||||
* dm_mdio_phy_connect - Wrapper over phy_connect for DM MDIO
|
||||
*
|
||||
* @dev: mdio dev
|
||||
* @addr: PHY address on MDIO bus
|
||||
* @ethdev: ethernet device to connect to the PHY
|
||||
* @interface: MAC-PHY protocol
|
||||
*
|
||||
* @return pointer to phy_device, or 0 on error
|
||||
*/
|
||||
struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr,
|
||||
struct udevice *ethdev,
|
||||
phy_interface_t interface);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -15,6 +15,7 @@ obj-$(CONFIG_NET) += eth-uclass.o
|
||||
else
|
||||
obj-$(CONFIG_NET) += eth_legacy.o
|
||||
endif
|
||||
obj-$(CONFIG_DM_MDIO) += mdio-uclass.o
|
||||
obj-$(CONFIG_NET) += eth_common.o
|
||||
obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
|
||||
obj-$(CONFIG_NET) += net.o
|
||||
|
115
net/mdio-uclass.c
Normal file
115
net/mdio-uclass.c
Normal file
@ -0,0 +1,115 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2019
|
||||
* Alex Marginean, NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <miiphy.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
|
||||
void dm_mdio_probe_devices(void)
|
||||
{
|
||||
struct udevice *it;
|
||||
struct uclass *uc;
|
||||
|
||||
uclass_get(UCLASS_MDIO, &uc);
|
||||
uclass_foreach_dev(it, uc) {
|
||||
device_probe(it);
|
||||
}
|
||||
}
|
||||
|
||||
static int dm_mdio_post_bind(struct udevice *dev)
|
||||
{
|
||||
/*
|
||||
* MDIO command doesn't like spaces in names, don't allow them to keep
|
||||
* it happy
|
||||
*/
|
||||
if (strchr(dev->name, ' ')) {
|
||||
debug("\nError: MDIO device name \"%s\" has a space!\n",
|
||||
dev->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Following read/write/reset functions are registered with legacy MII code.
|
||||
* These are called for PHY operations by upper layers and we further call the
|
||||
* DM MDIO driver functions.
|
||||
*/
|
||||
static int mdio_read(struct mii_dev *mii_bus, int addr, int devad, int reg)
|
||||
{
|
||||
struct udevice *dev = mii_bus->priv;
|
||||
|
||||
return mdio_get_ops(dev)->read(dev, addr, devad, reg);
|
||||
}
|
||||
|
||||
static int mdio_write(struct mii_dev *mii_bus, int addr, int devad, int reg,
|
||||
u16 val)
|
||||
{
|
||||
struct udevice *dev = mii_bus->priv;
|
||||
|
||||
return mdio_get_ops(dev)->write(dev, addr, devad, reg, val);
|
||||
}
|
||||
|
||||
static int mdio_reset(struct mii_dev *mii_bus)
|
||||
{
|
||||
struct udevice *dev = mii_bus->priv;
|
||||
|
||||
if (mdio_get_ops(dev)->reset)
|
||||
return mdio_get_ops(dev)->reset(dev);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dm_mdio_post_probe(struct udevice *dev)
|
||||
{
|
||||
struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev);
|
||||
|
||||
pdata->mii_bus = mdio_alloc();
|
||||
pdata->mii_bus->read = mdio_read;
|
||||
pdata->mii_bus->write = mdio_write;
|
||||
pdata->mii_bus->reset = mdio_reset;
|
||||
pdata->mii_bus->priv = dev;
|
||||
strncpy(pdata->mii_bus->name, dev->name, MDIO_NAME_LEN);
|
||||
|
||||
return mdio_register(pdata->mii_bus);
|
||||
}
|
||||
|
||||
static int dm_mdio_pre_remove(struct udevice *dev)
|
||||
{
|
||||
struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev);
|
||||
struct mdio_ops *ops = mdio_get_ops(dev);
|
||||
|
||||
if (ops->reset)
|
||||
ops->reset(dev);
|
||||
mdio_unregister(pdata->mii_bus);
|
||||
mdio_free(pdata->mii_bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr,
|
||||
struct udevice *ethdev,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev);
|
||||
|
||||
if (device_probe(dev))
|
||||
return 0;
|
||||
|
||||
return phy_connect(pdata->mii_bus, addr, ethdev, interface);
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(mdio) = {
|
||||
.id = UCLASS_MDIO,
|
||||
.name = "mdio",
|
||||
.post_bind = dm_mdio_post_bind,
|
||||
.post_probe = dm_mdio_post_probe,
|
||||
.pre_remove = dm_mdio_pre_remove,
|
||||
.per_device_auto_alloc_size = sizeof(struct mdio_perdev_priv),
|
||||
};
|
@ -62,4 +62,5 @@ obj-$(CONFIG_SOUND) += sound.o
|
||||
obj-$(CONFIG_TEE) += tee.o
|
||||
obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o
|
||||
obj-$(CONFIG_DMA) += dma.o
|
||||
obj-$(CONFIG_DM_MDIO) += mdio.o
|
||||
endif
|
||||
|
53
test/dm/mdio.c
Normal file
53
test/dm/mdio.c
Normal file
@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2019
|
||||
* Alex Marginean, NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/test.h>
|
||||
#include <misc.h>
|
||||
#include <test/ut.h>
|
||||
#include <miiphy.h>
|
||||
|
||||
/* macros copied over from mdio_sandbox.c */
|
||||
#define SANDBOX_PHY_ADDR 5
|
||||
#define SANDBOX_PHY_REG 0
|
||||
|
||||
#define TEST_REG_VALUE 0xabcd
|
||||
|
||||
static int dm_test_mdio(struct unit_test_state *uts)
|
||||
{
|
||||
struct uclass *uc;
|
||||
struct udevice *dev;
|
||||
struct mdio_ops *ops;
|
||||
u16 reg;
|
||||
|
||||
ut_assertok(uclass_get(UCLASS_MDIO, &uc));
|
||||
|
||||
ut_assertok(uclass_get_device_by_name(UCLASS_MDIO, "mdio-test", &dev));
|
||||
|
||||
ops = mdio_get_ops(dev);
|
||||
ut_assertnonnull(ops);
|
||||
ut_assertnonnull(ops->read);
|
||||
ut_assertnonnull(ops->write);
|
||||
|
||||
ut_assertok(ops->write(dev, SANDBOX_PHY_ADDR, MDIO_DEVAD_NONE,
|
||||
SANDBOX_PHY_REG, TEST_REG_VALUE));
|
||||
reg = ops->read(dev, SANDBOX_PHY_ADDR, MDIO_DEVAD_NONE,
|
||||
SANDBOX_PHY_REG);
|
||||
ut_asserteq(reg, TEST_REG_VALUE);
|
||||
|
||||
ut_assert(ops->read(dev, SANDBOX_PHY_ADDR + 1, MDIO_DEVAD_NONE,
|
||||
SANDBOX_PHY_REG) != 0);
|
||||
|
||||
ut_assertok(ops->reset(dev));
|
||||
reg = ops->read(dev, SANDBOX_PHY_ADDR, MDIO_DEVAD_NONE,
|
||||
SANDBOX_PHY_REG);
|
||||
ut_asserteq(reg, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DM_TEST(dm_test_mdio, DM_TESTF_SCAN_FDT);
|
Loading…
Reference in New Issue
Block a user