mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
ethernet: initial add the MAC and PHY driver
PD#131267: eth: initial add the MAC and PHY driver 1.internal eth phy supported 2.external eth phy supported 3.internal external phy can be switched by modify dts file Change-Id: Id5e17b7fe0bef31ccf1c56d86764ef4bcb610a46 Signed-off-by: Yizhou Jiang <yizhou.jiang@amlogic.com> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
This commit is contained in:
committed by
Jianxin Pan
parent
f4f9e5f344
commit
467f3a6a87
@@ -13495,3 +13495,8 @@ F: drivers/amlogic/i2c/aml_slave.h
|
||||
F: drivers/amlogic/i2c/Kconfig
|
||||
F: drivers/amlogic/i2c/Makefile
|
||||
|
||||
AMLOGIC internal phy driver for ethernet
|
||||
M: Yizhou Jiang <yizhou.jiang@amlogic.com
|
||||
F: drivers/amlogic/ethernet/*
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include "mesongxl.dtsi"
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/gpio/gxl.h>
|
||||
/ {
|
||||
model = "Amlogic";
|
||||
amlogic-dt-id = "gxl_p212_1g";
|
||||
@@ -115,6 +117,26 @@
|
||||
support-sysrq = <0>; /* 0 not support , 1 support */
|
||||
};
|
||||
|
||||
ethmac: ethernet@0xc9410000 {
|
||||
compatible = "amlogic, gxbb-eth-dwmac";
|
||||
reg = <0x0 0xc9410000 0x0 0x10000
|
||||
0x0 0xc8834540 0x0 0x8
|
||||
0x0 0xc8834558 0x0 0xc>;
|
||||
interrupts = <0 8 1>;
|
||||
pinctrl-names = "external_eth_pins";
|
||||
pinctrl-0 = <&external_eth_pins>;
|
||||
rst_pin-gpios = <&gpio GPIOZ_14 0>;
|
||||
GPIOZ4_pin-gpios = <&gpio GPIOZ_4 0>;
|
||||
GPIOZ5_pin-gpios = <&gpio GPIOZ_5 0>;
|
||||
mc_val_internal_phy = <0x1800>;
|
||||
mc_val_external_phy = <0x1621>;
|
||||
cali_val = <0x20000>;
|
||||
interrupt-names = "macirq";
|
||||
clocks = <&clkc CLKID_ETH>;
|
||||
clock-names = "ethclk81";
|
||||
internal_phy=<1>;
|
||||
};
|
||||
|
||||
dwc3: dwc3@c9000000 {
|
||||
compatible = "synopsys, dwc3";
|
||||
reg = <0x0 0xc9000000 0x0 0x100000>;
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/gpio/gxl.h>
|
||||
#include "mesongxl.dtsi"
|
||||
/ {
|
||||
model = "Amlogic";
|
||||
@@ -114,6 +116,25 @@
|
||||
pinctrl-0 = <&ao_uart_pins>;
|
||||
support-sysrq = <0>; /* 0 not support , 1 support */
|
||||
};
|
||||
ethmac: ethernet@0xc9410000 {
|
||||
compatible = "amlogic, gxbb-eth-dwmac";
|
||||
reg = <0x0 0xc9410000 0x0 0x10000
|
||||
0x0 0xc8834540 0x0 0x8
|
||||
0x0 0xc8834558 0x0 0xc>;
|
||||
interrupts = <0 8 1>;
|
||||
pinctrl-names = "external_eth_pins";
|
||||
pinctrl-0 = <&external_eth_pins>;
|
||||
rst_pin-gpios = <&gpio GPIOZ_14 0>;
|
||||
GPIOZ4_pin-gpios = <&gpio GPIOZ_4 0>;
|
||||
GPIOZ5_pin-gpios = <&gpio GPIOZ_5 0>;
|
||||
mc_val_internal_phy = <0x1800>;
|
||||
mc_val_external_phy = <0x1621>;
|
||||
cali_val = <0x20000>;
|
||||
interrupt-names = "macirq";
|
||||
clocks = <&clkc CLKID_ETH>;
|
||||
clock-names = "ethclk81";
|
||||
internal_phy=<1>;
|
||||
};
|
||||
|
||||
dwc3: dwc3@c9000000 {
|
||||
compatible = "synopsys, dwc3";
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include "mesongxm.dtsi"
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/gpio/gxl.h>
|
||||
/ {
|
||||
model = "Amlogic";
|
||||
amlogic-dt-id = "gxm_q200_2g";
|
||||
@@ -110,6 +112,26 @@
|
||||
support-sysrq = <0>; /* 0 not support , 1 support */
|
||||
};
|
||||
|
||||
ethmac: ethernet@0xc9410000 {
|
||||
compatible = "amlogic, gxbb-eth-dwmac";
|
||||
reg = <0x0 0xc9410000 0x0 0x10000
|
||||
0x0 0xc8834540 0x0 0x8
|
||||
0x0 0xc8834558 0x0 0xc>;
|
||||
interrupts = <0 8 1>;
|
||||
pinctrl-names = "external_eth_pins";
|
||||
pinctrl-0 = <&external_eth_pins>;
|
||||
rst_pin-gpios = <&gpio GPIOZ_14 0>;
|
||||
GPIOZ4_pin-gpios = <&gpio GPIOZ_4 0>;
|
||||
GPIOZ5_pin-gpios = <&gpio GPIOZ_5 0>;
|
||||
mc_val_internal_phy = <0x1800>;
|
||||
mc_val_external_phy = <0x1621>;
|
||||
cali_val = <0x20000>;
|
||||
interrupt-names = "macirq";
|
||||
clocks = <&clkc CLKID_ETH>;
|
||||
clock-names = "ethclk81";
|
||||
internal_phy=<1>;
|
||||
};
|
||||
|
||||
dwc3: dwc3@c9000000 {
|
||||
compatible = "synopsys, dwc3";
|
||||
reg = <0x0 0xc9000000 0x0 0x100000>;
|
||||
|
||||
@@ -456,7 +456,7 @@
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
eth_pins:eth_pins {
|
||||
external_eth_pins:external_eth_pins {
|
||||
mux {
|
||||
groups = "eth_mdio",
|
||||
"eth_mdc",
|
||||
|
||||
@@ -508,7 +508,7 @@
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
eth_pins:eth_pins {
|
||||
external_eth_pins:external_eth_pins {
|
||||
mux {
|
||||
groups = "eth_mdio",
|
||||
"eth_mdc",
|
||||
|
||||
@@ -184,6 +184,7 @@ CONFIG_AMLOGIC_ADC_KEYPADS=y
|
||||
CONFIG_AMLOGIC_SARADC=y
|
||||
CONFIG_AMLOGIC_EFUSE=y
|
||||
CONFIG_AMLOGIC_REBOOT=y
|
||||
CONFIG_AMLOGIC_INTERNAL_PHY=y
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
@@ -210,6 +211,8 @@ CONFIG_DM_VERITY=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_TUN=y
|
||||
CONFIG_STMMAC_ETH=y
|
||||
CONFIG_DWMAC_MESON=y
|
||||
CONFIG_AMLOGIC_ETH_PRIVE=y
|
||||
CONFIG_ICPLUS_PHY=y
|
||||
CONFIG_REALTEK_PHY=y
|
||||
CONFIG_PPP=y
|
||||
|
||||
@@ -42,5 +42,8 @@ source "drivers/amlogic/input/Kconfig"
|
||||
source "drivers/amlogic/efuse/Kconfig"
|
||||
|
||||
source "drivers/amlogic/reboot/Kconfig"
|
||||
|
||||
source "drivers/amlogic/ethernet/phy/Kconfig"
|
||||
|
||||
endmenu
|
||||
endif
|
||||
|
||||
@@ -38,3 +38,6 @@ obj-$(CONFIG_AMLOGIC_INPUT) += input/
|
||||
obj-$(CONFIG_AMLOGIC_EFUSE) += efuse/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_REBOOT) += reboot/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_INTERNAL_PHY) += ethernet/phy/
|
||||
|
||||
|
||||
12
drivers/amlogic/ethernet/phy/Kconfig
Normal file
12
drivers/amlogic/ethernet/phy/Kconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# PHY Layer Configuration
|
||||
#
|
||||
|
||||
config AMLOGIC_INTERNAL_PHY
|
||||
tristate "Drivers for amlogic internal phy"
|
||||
---help---
|
||||
Currently supports the amlogic internal phy.
|
||||
This module implements the amlogic internal phy,
|
||||
modify the dts file to switch internal external phy.
|
||||
|
||||
if in doube, ask yizhou.
|
||||
3
drivers/amlogic/ethernet/phy/Makefile
Normal file
3
drivers/amlogic/ethernet/phy/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
# Makefile for amlogic PHY drivers
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_INTERNAL_PHY) += amlogic.o
|
||||
268
drivers/amlogic/ethernet/phy/amlogic.c
Normal file
268
drivers/amlogic/ethernet/phy/amlogic.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* drivers/amlogic/ethernet/phy/amlogic.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/phy.h>
|
||||
|
||||
#define SMI_ADDR_TSTWRITE 23
|
||||
|
||||
MODULE_DESCRIPTION("amlogic internal ethernet phy driver");
|
||||
MODULE_AUTHOR("Yizhou Jiang");
|
||||
MODULE_LICENSE("GPL");
|
||||
void set_a3_config(struct phy_device *phydev)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
phy_write(phydev, 0x17, 0xa900);
|
||||
phy_write(phydev, 0x14, 0x4414);
|
||||
phy_write(phydev, 0x14, 0x8680);
|
||||
value = phy_read(phydev, 0x15);
|
||||
}
|
||||
|
||||
void internal_wol_init(struct phy_device *phydev)
|
||||
{
|
||||
int val;
|
||||
unsigned char *mac_addr;
|
||||
|
||||
mac_addr = phydev->attached_dev->dev_addr;
|
||||
/*chose wol register bank*/
|
||||
val = phy_read(phydev, 0x14);
|
||||
val |= 0x800;
|
||||
val &= ~0x1000;
|
||||
phy_write(phydev, 0x14, val);/*write data to wol register bank*/
|
||||
/*write mac address*/
|
||||
phy_write(phydev, SMI_ADDR_TSTWRITE, mac_addr[0] | mac_addr[1] << 8);
|
||||
phy_write(phydev, 0x14, 0x4800 | 0x00);
|
||||
phy_write(phydev, SMI_ADDR_TSTWRITE, mac_addr[2] | mac_addr[3] << 8);
|
||||
phy_write(phydev, 0x14, 0x4800 | 0x01);
|
||||
phy_write(phydev, SMI_ADDR_TSTWRITE, mac_addr[4] | mac_addr[5] << 8);
|
||||
phy_write(phydev, 0x14, 0x4800 | 0x02);
|
||||
/*enable wol*/
|
||||
phy_write(phydev, SMI_ADDR_TSTWRITE, 0x9);
|
||||
phy_write(phydev, 0x14, 0x4800 | 0x03);
|
||||
/*enable interrupt*/
|
||||
phy_write(phydev, 0x1E, 0xe00);
|
||||
}
|
||||
|
||||
void internal_config(struct phy_device *phydev)
|
||||
{
|
||||
int value;
|
||||
/*set reg27[12] = 1*/
|
||||
value = phy_read(phydev, 0x1b);
|
||||
phy_write(phydev, 0x1b, value | 0x1000);
|
||||
phy_write(phydev, 0x11, 0x0080);
|
||||
/*Enable Analog and DSP register Bank access by*/
|
||||
phy_write(phydev, 0x14, 0x0000);
|
||||
phy_write(phydev, 0x14, 0x0400);
|
||||
phy_write(phydev, 0x14, 0x0000);
|
||||
phy_write(phydev, 0x14, 0x0400);
|
||||
/*Write Analog register 23*/
|
||||
phy_write(phydev, 0x17, 0x8E0D);
|
||||
phy_write(phydev, 0x14, 0x4417);
|
||||
/*Enable fractional PLL*/
|
||||
phy_write(phydev, 0x17, 0x0005);
|
||||
phy_write(phydev, 0x14, 0x5C1B);
|
||||
/*Programme fraction FR_PLL_DIV1*/
|
||||
phy_write(phydev, 0x17, 0x029A);
|
||||
phy_write(phydev, 0x14, 0x5C1D);
|
||||
/*programme fraction FR_PLL_DiV1*/
|
||||
phy_write(phydev, 0x17, 0xAAAA);
|
||||
phy_write(phydev, 0x14, 0x5C1C);
|
||||
phy_write(phydev, 0x17, 0x000c);
|
||||
phy_write(phydev, 0x14, 0x4418);
|
||||
phy_write(phydev, 0x17, 0x1A0C);
|
||||
phy_write(phydev, 0x14, 0x4417); /* A6_CONFIG */
|
||||
phy_write(phydev, 0x17, 0x6400);
|
||||
phy_write(phydev, 0x14, 0x441A); /* A8_CONFIG */
|
||||
pr_info("internal phy init\n");
|
||||
}
|
||||
|
||||
void reset_internal_phy(struct phy_device *phydev)
|
||||
{
|
||||
int value;
|
||||
/*get value of bit 15:8*/
|
||||
/*if get 1, means power down reset or warm reset*/
|
||||
if (phydev->drv->features & 0xff00) {
|
||||
pr_info("power down and up\n");
|
||||
value = phy_read(phydev, MII_BMCR);
|
||||
phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
|
||||
msleep(50);
|
||||
value = phy_read(phydev, MII_BMCR);
|
||||
phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
phy_write(phydev, MII_BMCR, BMCR_RESET);
|
||||
msleep(50);
|
||||
internal_config(phydev);
|
||||
pr_info("reset phy\n");
|
||||
}
|
||||
|
||||
static int internal_phy_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
int reg31 = 0;
|
||||
int wol_reg12;
|
||||
int linkup = 0;
|
||||
int val;
|
||||
static int reg12_error_count;
|
||||
/* Update the link, but return if there was an error */
|
||||
/* Bit 15: READ*/
|
||||
/*Bit 14: Write*/
|
||||
/*Bit 12:11: BANK_SEL (0: DSP, 1: WOL, 3: BIST)*/
|
||||
/*Bit 10: Test Mode*/
|
||||
/*Bit 9:5: Read Address*/
|
||||
/*Bit 4:0: Write Address*/
|
||||
/*read wol bank reg12*/
|
||||
val = ((1 << 15) | (1 << 11) | (1 << 10) | (12 << 5));
|
||||
phy_write(phydev, 0x14, val);
|
||||
wol_reg12 = phy_read(phydev, 0x15);
|
||||
if (phydev->link) {
|
||||
if ((wol_reg12 & 0x1000))
|
||||
reg12_error_count = 0;
|
||||
if (!(wol_reg12 & 0x1000)) {
|
||||
reg12_error_count++;
|
||||
pr_info("wol_reg12[12]==0, error\n");
|
||||
}
|
||||
if (reg12_error_count >= (phydev->drv->features & 0xff)) {
|
||||
reg12_error_count = 0;
|
||||
reset_internal_phy(phydev);
|
||||
}
|
||||
} else {
|
||||
reg12_error_count = 0;
|
||||
}
|
||||
linkup = phydev->link;
|
||||
err = genphy_update_link(phydev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
phydev->lp_advertising = 0;
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE) {
|
||||
/*read internal phy reg 0x1f*/
|
||||
reg31 = phy_read(phydev, 0x1f);
|
||||
/*bit 12 auto negotiation done*/
|
||||
if (reg31 | 0x1000) {
|
||||
phydev->pause = 0;
|
||||
phydev->asym_pause = 0;
|
||||
phydev->speed = SPEED_10;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
/*bit 4:2 speed indication*/
|
||||
reg31 &= 0x1c;
|
||||
/*value 001: 10M/half*/
|
||||
if (reg31 == 0x4) {
|
||||
phydev->speed = SPEED_10;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
}
|
||||
/*value 101: 10M/full*/
|
||||
if (reg31 == 0x14) {
|
||||
phydev->speed = SPEED_10;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
}
|
||||
/*value 010: 100M/half*/
|
||||
if (reg31 == 0x8) {
|
||||
phydev->speed = SPEED_100;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
}
|
||||
/*value 110: 100M/full*/
|
||||
if (reg31 == 0x18) {
|
||||
phydev->speed = SPEED_100;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int bmcr = phy_read(phydev, MII_BMCR);
|
||||
|
||||
if (bmcr < 0)
|
||||
return bmcr;
|
||||
|
||||
if (bmcr & BMCR_FULLDPLX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
if (bmcr & BMCR_SPEED1000)
|
||||
phydev->speed = SPEED_1000;
|
||||
else if (bmcr & BMCR_SPEED100)
|
||||
phydev->speed = SPEED_100;
|
||||
else
|
||||
phydev->speed = SPEED_10;
|
||||
|
||||
phydev->pause = 0;
|
||||
phydev->asym_pause = 0;
|
||||
}
|
||||
/*every time link up, set a3 config*/
|
||||
if ((linkup == 0) && (phydev->link == 1)) {
|
||||
if (phydev->speed == SPEED_100)
|
||||
set_a3_config(phydev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int internal_config_init(struct phy_device *phydev)
|
||||
{
|
||||
/*internal_wol_init(phydev);*/
|
||||
internal_config(phydev);
|
||||
return genphy_config_init(phydev);
|
||||
}
|
||||
|
||||
static int internal_phy_resume(struct phy_device *phydev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = genphy_resume(phydev);
|
||||
phy_init_hw(phydev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct phy_driver amlogic_internal_driver[] = { {
|
||||
.phy_id = 0x01814400,
|
||||
.name = "amlogic internal phy",
|
||||
.phy_id_mask = 0x0fffffff,
|
||||
.config_init = internal_config_init,
|
||||
/*1 means power down reset, 0 means marm reset*/
|
||||
/*bit 0-7,value f:count_sec=15*/
|
||||
.features = 0x10f,
|
||||
.config_aneg = genphy_config_aneg,
|
||||
.read_status = internal_phy_read_status,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = internal_phy_resume,
|
||||
} };
|
||||
|
||||
module_phy_driver(amlogic_internal_driver);
|
||||
|
||||
static struct mdio_device_id __maybe_unused amlogic_tbl[] = {
|
||||
{ 0x01814400, 0xfffffff0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(mdio, amlogic_tbl);
|
||||
@@ -60,8 +60,8 @@ config DWMAC_LPC18XX
|
||||
|
||||
config DWMAC_MESON
|
||||
tristate "Amlogic Meson dwmac support"
|
||||
default ARCH_MESON
|
||||
depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST)
|
||||
default n
|
||||
depends on OF && COMMON_CLK
|
||||
help
|
||||
Support for Ethernet controller on Amlogic Meson SoCs.
|
||||
|
||||
@@ -69,6 +69,17 @@ config DWMAC_MESON
|
||||
the stmmac device driver. This driver is used for Meson6,
|
||||
Meson8, Meson8b and GXBB SoCs.
|
||||
|
||||
config AMLOGIC_ETH_PRIVE
|
||||
tristate "Amlogic private ethernet code"
|
||||
default n
|
||||
depends on OF
|
||||
help
|
||||
Support for Ethernet controller on Amlogic Meson SoCs.
|
||||
|
||||
This selects the Amlogic Meson SoC glue layer support for
|
||||
the stmmac device driver. This driver is used for amlogic
|
||||
private driver.
|
||||
|
||||
config DWMAC_ROCKCHIP
|
||||
tristate "Rockchip dwmac support"
|
||||
default ARCH_ROCKCHIP
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/stmmac.h>
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include "dwmac1000.h"
|
||||
#include "dwmac_dma.h"
|
||||
#endif
|
||||
#include "stmmac_platform.h"
|
||||
|
||||
#define ETHMAC_SPEED_100 BIT(1)
|
||||
@@ -47,6 +51,106 @@ static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed)
|
||||
writel(val, dwmac->reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
|
||||
#define ETH_REG2_REVERSED BIT(28)
|
||||
#define INTERNAL_PHY_ID 0x110181
|
||||
#define PHY_ENABLE BIT(31)
|
||||
#define USE_PHY_IP BIT(30)
|
||||
#define CLK_IN_EN BIT(29)
|
||||
#define USE_PHY_MDI BIT(26)
|
||||
#define LED_POLARITY BIT(23)
|
||||
#define ETH_REG3_19_RESVERD (0x9 << 16)
|
||||
#define CFG_PHY_ADDR (0x8 << 8)
|
||||
#define CFG_MODE (0x7 << 4)
|
||||
#define CFG_EN_HIGH BIT(3)
|
||||
#define ETH_REG3_2_RESERVED 0x7
|
||||
static void __iomem *network_interface_setup(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_desc *gdesc;
|
||||
struct gpio_desc *gdesc_z4;
|
||||
struct gpio_desc *gdesc_z5;
|
||||
struct pinctrl *pin_ctl;
|
||||
struct resource *res;
|
||||
u32 mc_val, cali_val, internal_phy;
|
||||
void __iomem *addr = NULL;
|
||||
void __iomem *PREG_ETH_REG0;
|
||||
void __iomem *PREG_ETH_REG1;
|
||||
void __iomem *PREG_ETH_REG2;
|
||||
void __iomem *PREG_ETH_REG3;
|
||||
void __iomem *PREG_ETH_REG4;
|
||||
|
||||
/*map reg0 and reg 1 addr.*/
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
addr = devm_ioremap_resource(dev, res);
|
||||
PREG_ETH_REG0 = addr;
|
||||
PREG_ETH_REG1 = addr + 4;
|
||||
pr_debug("REG0:REG1 = %p :%p\n", PREG_ETH_REG0, PREG_ETH_REG1);
|
||||
|
||||
if (!of_property_read_u32(np, "internal_phy", &internal_phy)) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
|
||||
addr = devm_ioremap_resource(dev, res);
|
||||
PREG_ETH_REG2 = addr;
|
||||
PREG_ETH_REG3 = addr + 4;
|
||||
PREG_ETH_REG4 = addr + 8;
|
||||
if (internal_phy == 1) {
|
||||
pr_debug("internal phy\n");
|
||||
/* Get mec mode & ting value set it in cbus2050 */
|
||||
if (of_property_read_u32(np, "mc_val_internal_phy",
|
||||
&mc_val)) {
|
||||
} else {
|
||||
writel(mc_val, addr);
|
||||
}
|
||||
writel(ETH_REG2_REVERSED | INTERNAL_PHY_ID,
|
||||
PREG_ETH_REG2);
|
||||
writel(PHY_ENABLE | USE_PHY_IP | CLK_IN_EN |
|
||||
USE_PHY_MDI | LED_POLARITY |
|
||||
ETH_REG3_19_RESVERD | CFG_PHY_ADDR |
|
||||
CFG_MODE | CFG_EN_HIGH |
|
||||
ETH_REG3_2_RESERVED, PREG_ETH_REG3);
|
||||
pin_ctl = devm_pinctrl_get_select
|
||||
(&pdev->dev, "internal_eth_pins");
|
||||
} else {
|
||||
/* Get mec mode & ting value set it in cbus2050 */
|
||||
if (of_property_read_u32(np, "mc_val_external_phy",
|
||||
&mc_val))
|
||||
writel(mc_val, addr);
|
||||
if (!of_property_read_u32(np, "cali_val", &cali_val))
|
||||
writel(cali_val, addr + 4);
|
||||
writel(ETH_REG2_REVERSED | INTERNAL_PHY_ID,
|
||||
PREG_ETH_REG2);
|
||||
writel(CLK_IN_EN | ETH_REG3_19_RESVERD |
|
||||
CFG_PHY_ADDR | CFG_MODE | CFG_EN_HIGH |
|
||||
ETH_REG3_2_RESERVED, PREG_ETH_REG3);
|
||||
/* pull reset pin for resetting phy */
|
||||
gdesc = gpiod_get(&pdev->dev, "rst_pin",
|
||||
GPIOD_FLAGS_BIT_DIR_OUT);
|
||||
gdesc_z4 = gpiod_get(&pdev->dev, "GPIOZ4_pin",
|
||||
GPIOD_FLAGS_BIT_DIR_OUT);
|
||||
gdesc_z5 = gpiod_get(&pdev->dev, "GPIOZ5_pin",
|
||||
GPIOD_FLAGS_BIT_DIR_OUT);
|
||||
if (!IS_ERR(gdesc) && !IS_ERR(gdesc_z4)) {
|
||||
gpiod_direction_output(gdesc_z4, 0);
|
||||
gpiod_direction_output(gdesc_z5, 0);
|
||||
gpiod_direction_output(gdesc, 0);
|
||||
mdelay(20);
|
||||
gpiod_direction_output(gdesc, 1);
|
||||
mdelay(100);
|
||||
gpiod_put(gdesc_z4);
|
||||
gpiod_put(gdesc_z5);
|
||||
pr_debug("Ethernet: gpio reset ok\n");
|
||||
}
|
||||
pin_ctl = devm_pinctrl_get_select
|
||||
(&pdev->dev, "external_eth_pins");
|
||||
}
|
||||
} else {
|
||||
pin_ctl = devm_pinctrl_get_select(&pdev->dev, "eth_pins");
|
||||
}
|
||||
pr_debug("Ethernet: pinmux setup ok\n");
|
||||
return addr;
|
||||
}
|
||||
#endif
|
||||
static int meson6_dwmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct plat_stmmacenet_data *plat_dat;
|
||||
@@ -78,6 +182,14 @@ static int meson6_dwmac_probe(struct platform_device *pdev)
|
||||
|
||||
plat_dat->bsp_priv = dwmac;
|
||||
plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed;
|
||||
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
|
||||
network_interface_setup(pdev); /* Custom initialisation (if needed) */
|
||||
if (plat_dat->init) {
|
||||
ret = plat_dat->init(pdev, plat_dat->bsp_priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
||||
if (ret)
|
||||
@@ -93,6 +205,9 @@ err_remove_config_dt:
|
||||
|
||||
static const struct of_device_id meson6_dwmac_match[] = {
|
||||
{ .compatible = "amlogic,meson6-dwmac" },
|
||||
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
|
||||
{ .compatible = "amlogic, gxbb-eth-dwmac" },
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson6_dwmac_match);
|
||||
|
||||
@@ -22,8 +22,11 @@
|
||||
|
||||
#ifndef __STMMAC_H__
|
||||
#define __STMMAC_H__
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
|
||||
#define STMMAC_RESOURCE_NAME "ethclk81"
|
||||
#else
|
||||
#define STMMAC_RESOURCE_NAME "stmmaceth"
|
||||
#endif
|
||||
#define DRV_MODULE_VERSION "Jan_2016"
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
||||
@@ -268,7 +268,11 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
|
||||
if (of_device_is_compatible(np, "st,spear600-gmac") ||
|
||||
of_device_is_compatible(np, "snps,dwmac-3.50a") ||
|
||||
of_device_is_compatible(np, "snps,dwmac-3.70a") ||
|
||||
of_device_is_compatible(np, "snps,dwmac")) {
|
||||
of_device_is_compatible(np, "snps,dwmac") ||
|
||||
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
|
||||
of_device_is_compatible(np, "amlogic, gxbb-eth-dwmac")
|
||||
#endif
|
||||
) {
|
||||
/* Note that the max-frame-size parameter as defined in the
|
||||
* ePAPR v1.1 spec is defined as max-frame-size, it's
|
||||
* actually used as the IEEE definition of MAC Client
|
||||
|
||||
@@ -526,9 +526,12 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
|
||||
r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
|
||||
if (r)
|
||||
return ERR_PTR(r);
|
||||
|
||||
/* If the phy_id is mostly Fs, there is no device there */
|
||||
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
|
||||
if (phy_id == 0 || ((phy_id & 0x1fffffff) == 0x1fffffff))
|
||||
#else
|
||||
if ((phy_id & 0x1fffffff) == 0x1fffffff)
|
||||
#endif
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
|
||||
|
||||
Reference in New Issue
Block a user