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:
Benjamin Perseghetti 2023-11-24 21:39:21 -05:00 committed by David Leach
parent d2ea187228
commit 0fa204b9fd
10 changed files with 326 additions and 6 deletions

View file

@ -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

View file

@ -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`_.

View file

@ -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>,

View file

@ -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";
};
};

View file

@ -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)

View file

@ -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

View 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)

View file

@ -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 {

View 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"

View file

@ -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 */