drivers: net: phy: add tja1103
Adds the tja1103 enet phy for setting phy options on the mr_canhubk3. Co-authored-by: Manuel Argüelles <manuel.arguelles@nxp.com> Co-authored-by: Peter van der Perk <peter.vanderperk@nxp.com> Signed-off-by: Benjamin Perseghetti <bperseghetti@rudislabs.com>
This commit is contained in:
parent
d2ea187228
commit
0fa204b9fd
|
@ -25,6 +25,9 @@ if NETWORKING
|
|||
config NET_L2_ETHERNET
|
||||
default y if !NET_LOOPBACK && !NET_TEST
|
||||
|
||||
config MDIO
|
||||
default y if NET_L2_ETHERNET
|
||||
|
||||
endif # NETWORKING
|
||||
|
||||
endif # BOARD_MR_CANHUBK3
|
||||
|
|
|
@ -31,7 +31,7 @@ Hardware
|
|||
- Console UART
|
||||
- 6x CAN FD
|
||||
- 100Base-T1 Ethernet
|
||||
- DroneCode standard JST-GH connectors and I/O headers for I2C, SPI, GPIO,
|
||||
- JST-GH connectors and I/O headers for I2C, SPI, GPIO,
|
||||
PWM, etc.
|
||||
|
||||
More information about the hardware and design resources can be found at
|
||||
|
@ -57,6 +57,7 @@ ADC SAR on-chip adc
|
|||
LPSPI on-chip spi
|
||||
WDT FS26 SBC watchdog
|
||||
EMAC on-chip ethernet
|
||||
mdio
|
||||
eMIOS on-chip pwm
|
||||
EDMA on-chip dma
|
||||
============ ========== ================================
|
||||
|
@ -252,9 +253,9 @@ Ethernet
|
|||
|
||||
This board has a single instance of Ethernet Media Access Controller (EMAC)
|
||||
interfacing with a `NXP TJA1103`_ 100Base-T1 Ethernet PHY. Currently, there is
|
||||
no driver for this PHY and this board default pin strapping configuration for
|
||||
limited driver for this PHY that allows for overiding the default pin strapping configuration for
|
||||
the PHY (RMII, master, autonomous mode enabled, polarity correction enabled)
|
||||
allows to use it without software configuration.
|
||||
to slave mode.
|
||||
|
||||
The 100Base-T1 signals are available in connector ``P9`` and can be converted to
|
||||
100Base-T using a Ethernet media converter such as `RDDRONE-T1ADAPT`_.
|
||||
|
|
|
@ -270,6 +270,18 @@
|
|||
};
|
||||
};
|
||||
|
||||
mdio0_default: mdio0_default {
|
||||
group1 {
|
||||
pinmux = <(PTD16_EMAC_MII_RMII_MDIO_O | PTD16_EMAC_MII_RMII_MDIO_I)>;
|
||||
input-enable;
|
||||
output-enable;
|
||||
};
|
||||
group2 {
|
||||
pinmux = <PTE8_EMAC_MII_RMII_MDC>;
|
||||
output-enable;
|
||||
};
|
||||
};
|
||||
|
||||
emios0_default: emios0_default {
|
||||
group1 {
|
||||
pinmux = <PTB12_EMIOS_0_CH0_X_O>, <PTB13_EMIOS_0_CH1_G_O>,
|
||||
|
|
|
@ -409,10 +409,18 @@
|
|||
phy-connection-type = "rmii";
|
||||
local-mac-address = [02 04 9f aa bb cc];
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
fixed-link {
|
||||
speed = <100>;
|
||||
full-duplex;
|
||||
&mdio0 {
|
||||
pinctrl-0 = <&mdio0_default>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
|
||||
phy: ethernet-phy@12 {
|
||||
compatible = "nxp,tja1103";
|
||||
status = "okay";
|
||||
reg = <0x12>;
|
||||
master-slave = "slave";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
|
||||
zephyr_library_sources_ifdef(CONFIG_PHY_GENERIC_MII phy_mii.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PHY_ADIN2111 phy_adin2111.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PHY_TJA1103 phy_tja1103.c)
|
||||
|
|
|
@ -39,6 +39,14 @@ config PHY_ADIN2111
|
|||
help
|
||||
Enable ADIN2111 PHY driver.
|
||||
|
||||
config PHY_TJA1103
|
||||
bool "TJA1103 PHY driver"
|
||||
default y
|
||||
depends on DT_HAS_NXP_TJA1103_ENABLED
|
||||
depends on MDIO
|
||||
help
|
||||
Enable TJA1103 PHY driver.
|
||||
|
||||
config PHY_AUTONEG_TIMEOUT_MS
|
||||
int "Auto-negotiation timeout value in milliseconds"
|
||||
default 4000
|
||||
|
|
247
drivers/ethernet/phy/phy_tja1103.c
Normal file
247
drivers/ethernet/phy/phy_tja1103.c
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright 2023 NXP
|
||||
* Copyright 2023 CogniPilot Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nxp_tja1103
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/net/phy.h>
|
||||
#include <zephyr/net/mii.h>
|
||||
#include <zephyr/net/mdio.h>
|
||||
#include <zephyr/drivers/mdio.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(phy_tja1103, CONFIG_PHY_LOG_LEVEL);
|
||||
|
||||
/* PHYs out of reset check retry delay */
|
||||
#define TJA1103_AWAIT_DELAY_POLL_US 15000U
|
||||
/* Number of retries for PHYs out of reset check */
|
||||
#define TJA1103_AWAIT_RETRY_COUNT 200U
|
||||
|
||||
/* TJA1103 PHY identifier */
|
||||
#define TJA1103_ID 0x1BB013
|
||||
|
||||
/* MMD30 - Device status register */
|
||||
#define TJA1103_DEVICE_CONTROL (0x0040U)
|
||||
#define TJA1103_DEVICE_CONTROL_GLOBAL_CFG_EN BIT(14)
|
||||
#define TJA1103_DEVICE_CONTROL_SUPER_CFG_EN BIT(13)
|
||||
/* Shared - PHY control register */
|
||||
#define TJA1103_PHY_CONTROL (0x8100U)
|
||||
#define TJA1103_PHY_CONTROL_CFG_EN BIT(14)
|
||||
/* Shared - PHY status register */
|
||||
#define TJA1103_PHY_STATUS (0x8102U)
|
||||
#define TJA1103_PHY_STATUS_LINK_STAT BIT(2)
|
||||
|
||||
struct phy_tja1103_config {
|
||||
const struct device *mdio;
|
||||
uint8_t phy_addr;
|
||||
uint8_t master_slave;
|
||||
};
|
||||
|
||||
struct phy_tja1103_data {
|
||||
struct phy_link_state state;
|
||||
struct k_sem sem;
|
||||
};
|
||||
|
||||
static inline int phy_tja1103_c22_read(const struct device *dev, uint16_t reg, uint16_t *val)
|
||||
{
|
||||
const struct phy_tja1103_config *const cfg = dev->config;
|
||||
|
||||
return mdio_read(cfg->mdio, cfg->phy_addr, reg, val);
|
||||
}
|
||||
|
||||
static inline int phy_tja1103_c22_write(const struct device *dev, uint16_t reg, uint16_t val)
|
||||
{
|
||||
const struct phy_tja1103_config *const cfg = dev->config;
|
||||
|
||||
return mdio_write(cfg->mdio, cfg->phy_addr, reg, val);
|
||||
}
|
||||
|
||||
static inline int phy_tja1103_c45_write(const struct device *dev, uint16_t devad, uint16_t reg,
|
||||
uint16_t val)
|
||||
{
|
||||
const struct phy_tja1103_config *cfg = dev->config;
|
||||
|
||||
return mdio_write_c45(cfg->mdio, cfg->phy_addr, devad, reg, val);
|
||||
}
|
||||
|
||||
static inline int phy_tja1103_c45_read(const struct device *dev, uint16_t devad, uint16_t reg,
|
||||
uint16_t *val)
|
||||
{
|
||||
const struct phy_tja1103_config *cfg = dev->config;
|
||||
|
||||
return mdio_read_c45(cfg->mdio, cfg->phy_addr, devad, reg, val);
|
||||
}
|
||||
|
||||
static int phy_tja1103_reg_read(const struct device *dev, uint16_t reg_addr, uint32_t *data)
|
||||
{
|
||||
const struct phy_tja1103_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
mdio_bus_enable(cfg->mdio);
|
||||
|
||||
ret = phy_tja1103_c22_read(dev, reg_addr, (uint16_t *)data);
|
||||
|
||||
mdio_bus_disable(cfg->mdio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int phy_tja1103_reg_write(const struct device *dev, uint16_t reg_addr, uint32_t data)
|
||||
{
|
||||
const struct phy_tja1103_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
mdio_bus_enable(cfg->mdio);
|
||||
|
||||
ret = phy_tja1103_c22_write(dev, reg_addr, (uint16_t)data);
|
||||
|
||||
mdio_bus_disable(cfg->mdio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int phy_tja1103_id(const struct device *dev, uint32_t *phy_id)
|
||||
{
|
||||
uint16_t val;
|
||||
|
||||
if (phy_tja1103_c22_read(dev, MII_PHYID1R, &val) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*phy_id = (val & UINT16_MAX) << 16;
|
||||
|
||||
if (phy_tja1103_c22_read(dev, MII_PHYID2R, &val) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*phy_id |= (val & UINT16_MAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int phy_tja1103_get_link_state(const struct device *dev, struct phy_link_state *state)
|
||||
{
|
||||
struct phy_tja1103_data *const data = dev->data;
|
||||
uint16_t val;
|
||||
|
||||
k_sem_take(&data->sem, K_FOREVER);
|
||||
|
||||
if (phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_STATUS, &val) >= 0) {
|
||||
|
||||
data->state.is_up = (val & TJA1103_PHY_STATUS_LINK_STAT) != 0;
|
||||
|
||||
memcpy(state, &data->state, sizeof(struct phy_link_state));
|
||||
}
|
||||
|
||||
k_sem_give(&data->sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int phy_tja1103_cfg_link(const struct device *dev, enum phy_link_speed adv_speeds)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
if (adv_speeds & LINK_FULL_100BASE_T) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int phy_tja1103_init(const struct device *dev)
|
||||
{
|
||||
const struct phy_tja1103_config *const cfg = dev->config;
|
||||
struct phy_tja1103_data *const data = dev->data;
|
||||
uint32_t phy_id = 0;
|
||||
uint16_t val;
|
||||
int ret;
|
||||
|
||||
data->state.is_up = false;
|
||||
data->state.speed = LINK_FULL_100BASE_T;
|
||||
|
||||
ret = WAIT_FOR(!phy_tja1103_id(dev, &phy_id) && phy_id == TJA1103_ID,
|
||||
TJA1103_AWAIT_RETRY_COUNT * TJA1103_AWAIT_DELAY_POLL_US,
|
||||
k_sleep(K_USEC(TJA1103_AWAIT_DELAY_POLL_US)));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable to obtain PHY ID for device 0x%x", cfg->phy_addr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* enable config registers */
|
||||
ret = phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_DEVICE_CONTROL,
|
||||
TJA1103_DEVICE_CONTROL_GLOBAL_CFG_EN |
|
||||
TJA1103_DEVICE_CONTROL_SUPER_CFG_EN);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_CONTROL,
|
||||
TJA1103_PHY_CONTROL_CFG_EN);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = phy_tja1103_c45_read(dev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Change master/slave mode if need */
|
||||
if (cfg->master_slave == 1) {
|
||||
val |= MDIO_PMA_PMD_BT1_CTRL_CFG_MST;
|
||||
} else if (cfg->master_slave == 2) {
|
||||
val &= ~MDIO_PMA_PMD_BT1_CTRL_CFG_MST;
|
||||
}
|
||||
|
||||
ret = phy_tja1103_c45_write(dev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL, val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for settings to go in affect before checking link */
|
||||
k_sleep(K_MSEC(400));
|
||||
|
||||
phy_tja1103_get_link_state(dev, &data->state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int phy_tja1103_link_cb_set(const struct device *dev, phy_callback_t cb, void *user_data)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(cb);
|
||||
ARG_UNUSED(user_data);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static const struct ethphy_driver_api phy_tja1103_api = {
|
||||
.get_link = phy_tja1103_get_link_state,
|
||||
.cfg_link = phy_tja1103_cfg_link,
|
||||
.link_cb_set = phy_tja1103_link_cb_set,
|
||||
.read = phy_tja1103_reg_read,
|
||||
.write = phy_tja1103_reg_write,
|
||||
};
|
||||
|
||||
#define TJA1103_INITIALIZE(n) \
|
||||
static const struct phy_tja1103_config phy_tja1103_config_##n = { \
|
||||
.phy_addr = DT_INST_REG_ADDR(n), \
|
||||
.mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \
|
||||
.master_slave = DT_INST_ENUM_IDX(n, master_slave), \
|
||||
}; \
|
||||
static struct phy_tja1103_data phy_tja1103_data_##n = { \
|
||||
.sem = Z_SEM_INITIALIZER(phy_tja1103_data_##n.sem, 1, 1), \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(n, &phy_tja1103_init, NULL, &phy_tja1103_data_##n, \
|
||||
&phy_tja1103_config_##n, POST_KERNEL, CONFIG_PHY_INIT_PRIORITY, \
|
||||
&phy_tja1103_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(TJA1103_INITIALIZE)
|
|
@ -631,6 +631,16 @@
|
|||
compatible = "nxp,s32-gmac";
|
||||
interrupts = <105 0>, <106 0>, <107 0>, <108 0>;
|
||||
interrupt-names = "common", "tx", "rx", "safety";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mdio0: mdio@40480200 {
|
||||
reg = <0x40480200 0x8>;
|
||||
compatible = "nxp,s32-gmac-mdio";
|
||||
clocks = <&clock NXP_S32_AIPS_PLAT_CLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
edma0: dma-controller@4020c000 {
|
||||
|
|
24
dts/bindings/ethernet/nxp,tja1103.yaml
Normal file
24
dts/bindings/ethernet/nxp,tja1103.yaml
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2023 NXP
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: TJA1103 PHY
|
||||
|
||||
compatible: "nxp,tja1103"
|
||||
|
||||
include: phy.yaml
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
description: PHY address
|
||||
|
||||
master-slave:
|
||||
type: string
|
||||
required: true
|
||||
description: |
|
||||
100BASE-T1 Specifies that either phy has to run in master / slave mode
|
||||
Default selects the mode set by the pinstrapping on the hardware design.
|
||||
enum:
|
||||
- "default"
|
||||
- "master"
|
||||
- "slave"
|
|
@ -110,6 +110,8 @@ enum mdio_opcode {
|
|||
#define MDIO_AN_T1_ADV_M 0x0203U
|
||||
/** BASE-T1 Auto-negotiation advertisement register [47:32] */
|
||||
#define MDIO_AN_T1_ADV_H 0x0204U
|
||||
/* BASE-T1 PMA/PMD control register */
|
||||
#define MDIO_PMA_PMD_BT1_CTRL 0x0834U
|
||||
|
||||
/* BASE-T1 Auto-negotiation Control register */
|
||||
/** Auto-negotiation Restart */
|
||||
|
@ -155,6 +157,10 @@ enum mdio_opcode {
|
|||
/* 10BASE-T1L High Level Transmit Operating Mode Ability */
|
||||
#define MDIO_AN_T1_ADV_H_10L_TX_HI BIT(13)
|
||||
|
||||
/* BASE-T1 PMA/PMD control register */
|
||||
/** BASE-T1 master/slave configuration */
|
||||
#define MDIO_PMA_PMD_BT1_CTRL_CFG_MST BIT(14)
|
||||
|
||||
|
||||
/* 10BASE-T1L registers */
|
||||
/** 10BASE-T1L PMA control */
|
||||
|
|
Loading…
Reference in a new issue