diff --git a/drivers/net/atlantic/Makefile b/drivers/net/atlantic/Makefile
index fc12e6a..6340588 100644
--- a/drivers/net/atlantic/Makefile
+++ b/drivers/net/atlantic/Makefile
@@ -21,6 +21,7 @@ LDLIBS += -lrte_ethdev -lrte_net
 LDLIBS += -lrte_bus_pci
 
 VPATH += $(SRCDIR)/hw_atl
+VPATH += $(SRCDIR)/macsec
 
 #
 # all source are stored in SRCS-y
@@ -33,5 +34,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_ATLANTIC_PMD) += hw_atl_llh.c
 SRCS-$(CONFIG_RTE_LIBRTE_ATLANTIC_PMD) += hw_atl_utils_fw2x.c
 SRCS-$(CONFIG_RTE_LIBRTE_ATLANTIC_PMD) += hw_atl_b0.c
 SRCS-$(CONFIG_RTE_LIBRTE_ATLANTIC_PMD) += rte_pmd_atlantic.c
+SRCS-$(CONFIG_RTE_LIBRTE_ATLANTIC_PMD) += mdio.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/atlantic/macsec/mdio.c b/drivers/net/atlantic/macsec/mdio.c
new file mode 100644
index 0000000..a662f58
--- /dev/null
+++ b/drivers/net/atlantic/macsec/mdio.c
@@ -0,0 +1,328 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Aquantia Corporation
+ */
+
+#include "errno.h"
+#include "../atl_hw_regs.h"
+#include "../atl_logs.h"
+#include "../hw_atl/hw_atl_llh.h"
+#include "../hw_atl/hw_atl_b0.h"
+#include "../hw_atl/hw_atl_b0_internal.h"
+#include "mdio.h"
+
+static inline uint32_t macValRead(uint32_t reg, uint32_t msk, uint32_t shift)
+{
+    return (reg & msk) >> shift;
+}
+
+static inline void macValWrite(uint32_t* reg, uint32_t msk, uint32_t shift, uint32_t val)
+{
+    *reg = (*reg & ~msk) | (val << shift);
+}
+
+static inline uint32_t macBitRead(uint32_t reg, uint32_t msk)
+{
+    return reg & msk;
+}
+
+static inline uint32_t regGlobalMdioInterface1Get(void *hw)
+{
+    return aq_hw_read_reg(hw, 0x280);
+}
+
+static inline void valGlobalMdioInterface1MdioClockEnableSet(uint32_t *reg, uint32_t val)
+{
+    macValWrite(reg, 0x00004000, 14, val);
+}
+
+static inline void regGlobalMdioInterface1Set(void *hw, uint32_t val)
+{
+    aq_hw_write_reg(hw, 0x280, val);
+}
+
+static inline void valGlobalMdioInterface4MdioAddressSet(uint32_t *reg, uint32_t val)
+{
+    macValWrite(reg, 0x0000FFFF, 0, val);
+}
+
+static inline void regGlobalMdioInterface4Set(void *hw, uint32_t val)
+{
+    aq_hw_write_reg(hw, 0x28C, val);
+}
+
+static inline void valGlobalMdioInterface2MdioExecuteOperationSet(uint32_t *reg, uint32_t val)
+{
+    macValWrite(reg, 0x00008000, 15, val);
+}
+
+static inline void valGlobalMdioInterface2MdioOpModeSet(uint32_t *reg, uint32_t val)
+{
+    macValWrite(reg, 0x00003000, 12, val);
+}
+
+static inline void valGlobalMdioInterface2MdioPhyAddressSet(uint32_t *reg, uint32_t val)
+{
+    macValWrite(reg, 0x000003FF, 0, val);
+}
+
+static inline void regGlobalMdioInterface2Set(void *hw, uint32_t val)
+{
+    aq_hw_write_reg(hw, 0x284, val);
+}
+
+static inline uint32_t regGlobalMdioInterface2Get(void *hw)
+{
+    return aq_hw_read_reg(hw, 0x284);
+}
+
+static inline void valGlobalMdioInterface3MdioWriteDataSet(uint32_t *reg, uint32_t val)
+{
+    macValWrite(reg, 0x0000FFFF, 0, val);
+}
+
+static inline void regGlobalMdioInterface3Set(void *hw, uint32_t val)
+{
+    aq_hw_write_reg(hw, 0x288, val);
+}
+
+static inline uint32_t regGlobalMdioInterface5Get(void *hw)
+{
+    return aq_hw_read_reg(hw, 0x290);
+}
+
+static inline uint32_t valGlobalMdioInterface5MdioReadDataGet(uint32_t reg)
+{
+    return macValRead(reg, 0x0000FFFF, 0);
+}
+
+static inline uint32_t bitGlobalMdioInterface2MdioBusyGet(uint32_t reg)
+{
+    return macBitRead(reg, 0x80000000);
+}
+
+
+/* Operation Mode for MDIO */
+#define MDIO_OP_NO 0 /* No Op */
+#define MDIO_OP_READ 1 /* Read Op */
+#define MDIO_OP_WRITE 2 /* Write Op */
+#define MDIO_OP_ADDR 3 /* Address Op */
+
+#define MDIO_COMMAND_TIMEOUT 100
+#define MDIO_SEMAPHORE_TIMEOUT_MS 30 /* msec. */
+
+
+/* 32 bits command + 32 bits preamble = 64 */
+#define MDIO_ONE_CMD_CLOCK_TICKS     64
+/* Wait 10 MDIO transactions */
+#define TIMEOUT_BUSY_WAIT_COUNT     ((MIPS_COUNT_HZ * MDIO_ONE_CMD_CLOCK_TICKS / MDIO_HZ) * 10)
+
+static int mdio_phy_addr = (0 << 5);
+
+
+static inline unsigned int mMdioBusyCheck(void *hw)
+{
+    return bitGlobalMdioInterface2MdioBusyGet(regGlobalMdioInterface2Get(hw));
+}
+
+static int mBusyWait(struct aq_hw_s *hw)
+{
+    unsigned i = 0;
+
+    for (i = 1000U; mMdioBusyCheck(hw) && i; i--){};
+
+    if (i == 0) {
+	PMD_DRV_LOG(ERR, "Mdio busy!!");
+	return 1;
+    }
+
+    return 0;
+}
+
+
+static inline void mSendPhyAddress(struct aq_hw_s *hw, unsigned int mmd, unsigned int addr)
+{
+    uint32_t reg;
+
+    /* Set MDIO Address (0x28c) */
+    reg = 0;
+    valGlobalMdioInterface4MdioAddressSet(&reg, addr);
+    regGlobalMdioInterface4Set(hw, reg);
+
+    /* Set MDIO Address Operation and PHY Address (0x284) */
+    reg = 0;
+    valGlobalMdioInterface2MdioExecuteOperationSet(&reg, 1);
+    valGlobalMdioInterface2MdioOpModeSet(&reg, MDIO_OP_ADDR);
+    valGlobalMdioInterface2MdioPhyAddressSet(&reg, mdio_phy_addr | mmd);
+    regGlobalMdioInterface2Set(hw, reg);
+}
+
+static void mSendDummyWriteCmd(struct aq_hw_s *hw)
+{
+    uint32_t reg;
+
+    // Set data (0x288)
+    reg = 0;
+    valGlobalMdioInterface3MdioWriteDataSet(&reg, 0);
+    regGlobalMdioInterface3Set(hw, reg);
+
+    // Write operation (0x284)
+    reg = 0;
+    valGlobalMdioInterface2MdioExecuteOperationSet(&reg, 1);
+    valGlobalMdioInterface2MdioOpModeSet(&reg, MDIO_OP_WRITE);
+    valGlobalMdioInterface2MdioPhyAddressSet(&reg, 0);
+    regGlobalMdioInterface2Set(hw, reg);
+}
+
+static inline void mSendReadCmd(struct aq_hw_s *hw, unsigned int mmd)
+{
+    uint32_t reg;
+
+    // Execute Read Operation (0x284)
+    reg = 0;
+    valGlobalMdioInterface2MdioExecuteOperationSet(&reg, 1);
+    valGlobalMdioInterface2MdioOpModeSet(&reg, MDIO_OP_READ);
+    valGlobalMdioInterface2MdioPhyAddressSet(&reg, mdio_phy_addr | mmd);
+    regGlobalMdioInterface2Set(hw, reg);
+}
+
+static inline void mSendWriteCmd(struct aq_hw_s *hw, unsigned int mmd)
+{
+    uint32_t reg;
+
+    // Execute Read Operation (0x284)
+    reg = 0;
+    valGlobalMdioInterface2MdioExecuteOperationSet(&reg, 1);
+    valGlobalMdioInterface2MdioOpModeSet(&reg, MDIO_OP_WRITE);
+    valGlobalMdioInterface2MdioPhyAddressSet(&reg, mdio_phy_addr | mmd);
+    regGlobalMdioInterface2Set(hw, reg);
+}
+
+static inline unsigned short int mReadData(struct aq_hw_s *hw)
+{
+    // Register 0x290
+    return valGlobalMdioInterface5MdioReadDataGet(regGlobalMdioInterface5Get(hw));
+}
+
+static inline void mWriteData(struct aq_hw_s *hw, unsigned short int val)
+{
+    uint32_t reg;
+
+    // Register 0x288
+    reg = 0;
+    valGlobalMdioInterface3MdioWriteDataSet(&reg, val);
+    regGlobalMdioInterface3Set(hw, reg);
+}
+
+
+static int __mdioRead(struct aq_hw_s *hw, unsigned int mmd, unsigned int addr, unsigned short int* data)
+{
+    int ret = -1;
+
+    /* Execute Address Operation */
+    if (mBusyWait(hw))
+        goto _exit;
+    mSendPhyAddress(hw, mmd, addr);
+
+    /* Dummy write transaction */
+    if (mBusyWait(hw))
+        goto _exit;
+    mSendDummyWriteCmd(hw);
+
+    /* Read command */
+    if (mBusyWait(hw))
+        goto _exit;
+    mSendReadCmd(hw, mmd);
+
+    /* Read MDIO Data */
+    if (mBusyWait(hw))
+        goto _exit;
+    *data = mReadData(hw);
+
+    ret = 0;
+
+_exit:
+    return ret;
+}
+
+static
+int __mdioWrite(struct aq_hw_s *hw, unsigned int mmd, unsigned int addr, unsigned short int data)
+{
+    int ret = -1;
+
+    /* Execute Address Operation */
+    if (mBusyWait(hw))
+        goto _exit;
+    mSendPhyAddress(hw, mmd, addr);
+
+    /* Dummy write transaction */
+    if (mBusyWait(hw))
+        goto _exit;
+    mSendDummyWriteCmd(hw);
+
+    /* Write command */
+    if (mBusyWait(hw))
+        goto _exit;
+    mWriteData(hw, data);
+    mSendWriteCmd(hw, mmd);
+
+    /* Expect completion of the operation */
+    if (mBusyWait(hw))
+        goto _exit;
+
+    ret = 0;
+
+_exit:
+    return ret;
+}
+
+int mdioRead(struct aq_hw_s *hw, unsigned int mmd, unsigned int addr, unsigned short int* data)
+{
+    uint32_t reg;
+    int ret;
+
+    // Send Dummy Transaction
+    if (mBusyWait(hw))
+        return -1;
+    mSendDummyWriteCmd(hw);
+
+    // Enable MDIO Clock (active low) (0x280)
+    reg = regGlobalMdioInterface1Get(hw);
+    valGlobalMdioInterface1MdioClockEnableSet(&reg, 0);
+    regGlobalMdioInterface1Set(hw, reg);
+
+    ret = __mdioRead(hw, mmd, addr, data);
+
+    // Disable MDIO Clock (0x280)
+    reg = regGlobalMdioInterface1Get(hw);
+    valGlobalMdioInterface1MdioClockEnableSet(&reg, 1);
+    regGlobalMdioInterface1Set(hw, reg);
+
+    return ret;
+}
+
+int mdioWrite(struct aq_hw_s *hw, unsigned int mmd, unsigned int addr, unsigned short int data)
+{
+    uint32_t reg;
+    int ret;
+
+    // Send Dummy Transaction
+    if (mBusyWait(hw))
+        return -1;
+    mSendDummyWriteCmd(hw);
+
+    // Enable MDIO Clock (active low) (0x280)
+    reg = regGlobalMdioInterface1Get(hw);
+    valGlobalMdioInterface1MdioClockEnableSet(&reg, 0);
+    regGlobalMdioInterface1Set(hw, reg);
+
+    ret = __mdioWrite(hw, mmd, addr, data);
+
+    // Disable MDIO Clock (0x280)
+    reg = regGlobalMdioInterface1Get(hw);
+    valGlobalMdioInterface1MdioClockEnableSet(&reg, 1);
+    regGlobalMdioInterface1Set(hw, reg);
+
+    return ret;
+}
+
+
diff --git a/drivers/net/atlantic/macsec/mdio.h b/drivers/net/atlantic/macsec/mdio.h
new file mode 100644
index 0000000..907f04f
--- /dev/null
+++ b/drivers/net/atlantic/macsec/mdio.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Aquantia Corporation
+ */
+
+#ifndef __MDIO_HH__
+#define __MDIO_HH__
+
+
+#include "../atl_types.h"
+#include "../hw_atl/hw_atl_utils.h"
+
+
+#define MMD_GLOBAL 0x1E
+
+
+int mdioRead(struct aq_hw_s *hw, unsigned int mmd, unsigned int addr, unsigned short int* data);
+int mdioWrite(struct aq_hw_s *hw, unsigned int mmd, unsigned int addr, unsigned short int data);
+
+#endif
diff --git a/drivers/net/atlantic/meson.build b/drivers/net/atlantic/meson.build
index 919d741..d1c66f4 100644
--- a/drivers/net/atlantic/meson.build
+++ b/drivers/net/atlantic/meson.build
@@ -12,4 +12,5 @@ sources = files(
 	'hw_atl/hw_atl_utils_fw2x.c',
 	'hw_atl/hw_atl_utils.c',
 	'rte_pmd_atlantic.c',
+	'macsec/mdio.c',
 )
