/* Top Registers */
 #define MVPP2_MH_REG(port)                     (0x5040 + 4 * (port))
 #define MVPP2_DSA_EXTENDED                     BIT(5)
+#define MVPP2_VER_ID_REG                       0x50b0
+#define MVPP2_VER_PP22                         0x10
+#define MVPP2_VER_PP23                         0x11
 
 /* Parser Registers */
 #define MVPP2_PRS_INIT_LOOKUP_REG              0x1000
 #define     MVPP22_GMAC_INT_SUM_MASK_LINK_STAT BIT(1)
 #define            MVPP22_GMAC_INT_SUM_MASK_PTP        BIT(2)
 
-/* Per-port XGMAC registers. PPv2.2 only, only for GOP port 0,
+/* Per-port XGMAC registers. PPv2.2 and PPv2.3, only for GOP port 0,
  * relative to port->base.
  */
 #define MVPP22_XLG_CTRL0_REG                   0x100
 #define     MVPP22_XLG_CTRL4_MACMODSELECT_GMAC BIT(12)
 #define     MVPP22_XLG_CTRL4_EN_IDLE_CHECK     BIT(14)
 
-/* SMI registers. PPv2.2 only, relative to priv->iface_base. */
+/* SMI registers. PPv2.2 and PPv2.3, relative to priv->iface_base. */
 #define MVPP22_SMI_MISC_CFG_REG                        0x1204
 #define     MVPP22_SMI_POLLING_EN              BIT(10)
 
 #define MVPP2_QUEUE_NEXT_DESC(q, index) \
        (((index) < (q)->last_desc) ? ((index) + 1) : 0)
 
-/* XPCS registers. PPv2.2 only */
+/* XPCS registers.PPv2.2 and PPv2.3 */
 #define MVPP22_MPCS_BASE(port)                 (0x7000 + (port) * 0x1000)
 #define MVPP22_MPCS_CTRL                       0x14
 #define     MVPP22_MPCS_CTRL_FWD_ERR_CONN      BIT(10)
 #define     MVPP22_MPCS_CLK_RESET_DIV_RATIO(n) ((n) << 4)
 #define     MVPP22_MPCS_CLK_RESET_DIV_SET      BIT(11)
 
-/* XPCS registers. PPv2.2 only */
+/* XPCS registers. PPv2.2 and PPv2.3 */
 #define MVPP22_XPCS_BASE(port)                 (0x7400 + (port) * 0x1000)
 #define MVPP22_XPCS_CFG0                       0x0
 #define     MVPP22_XPCS_CFG0_RESET_DIS         BIT(0)
        void __iomem *iface_base;
        void __iomem *cm3_base;
 
-       /* On PPv2.2, each "software thread" can access the base
+       /* On PPv2.2 and PPv2.3, each "software thread" can access the base
         * register through a separate address space, each 64 KB apart
         * from each other. Typically, such address spaces will be
         * used per CPU.
         */
        void __iomem *swth_base[MVPP2_MAX_THREADS];
 
-       /* On PPv2.2, some port control registers are located into the system
-        * controller space. These registers are accessible through a regmap.
+       /* On PPv2.2 and PPv2.3, some port control registers are located into
+        * the system controller space. These registers are accessible
+        * through a regmap.
         */
        struct regmap *sysctrl_base;
 
        u32 tclk;
 
        /* HW version */
-       enum { MVPP21, MVPP22 } hw_version;
+       enum { MVPP21, MVPP22, MVPP23 } hw_version;
 
        /* Maximum number of RXQs per port */
        unsigned int max_port_rxqs;
        __le32 reserved8;
 };
 
-/* HW TX descriptor for PPv2.2 */
+/* HW TX descriptor for PPv2.2 and PPv2.3 */
 struct mvpp22_tx_desc {
        __le32 command;
        u8  packet_offset;
        __le64 buf_cookie_misc;
 };
 
-/* HW RX descriptor for PPv2.2 */
+/* HW RX descriptor for PPv2.2 and PPv2.3 */
 struct mvpp22_rx_desc {
        __le32 status;
        __le16 reserved1;
 
        if (!IS_ALIGNED(size, 16))
                return -EINVAL;
 
-       /* PPv2.1 needs 8 bytes per buffer pointer, PPv2.2 needs 16
+       /* PPv2.1 needs 8 bytes per buffer pointer, PPv2.2 and PPv2.3 needs 16
         * bytes per buffer pointer
         */
        if (priv->hw_version == MVPP21)
                return;
        }
 
-       /* Handle the more complicated PPv2.2 case */
+       /* Handle the more complicated PPv2.2 and PPv2.3 case */
        for (i = 0; i < port->nqvecs; i++) {
                struct mvpp2_queue_vector *qv = port->qvecs + i;
 
 
 /* Checks if the port dt description has the required Tx interrupts:
  * - PPv2.1: there are no such interrupts.
- * - PPv2.2:
+ * - PPv2.2 and PPv2.3:
  *   - The old DTs have: "rx-shared", "tx-cpuX" with X in [0...3]
  *   - The new ones have: "hifX" with X in [0..8]
  *
        mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port), attr_size);
 }
 
-/* Initialize TX FIFO's: the total FIFO size is 48kB on PPv2.2.
+/* Initialize TX FIFO's: the total FIFO size is 48kB on PPv2.2 and PPv2.3.
  * 4kB fixed space must be assigned for the loopback port.
  * Redistribute remaining avialable 44kB space among all active ports.
  * Guarantee minimum 32kB for 10G port and 8kB for port 1, capable of 2.5G
        mvpp2_write(priv, MVPP22_TX_FIFO_THRESH_REG(port), threshold);
 }
 
-/* Initialize TX FIFO's: the total FIFO size is 19kB on PPv2.2.
+/* Initialize TX FIFO's: the total FIFO size is 19kB on PPv2.2 and PPv2.3.
  * 3kB fixed space must be assigned for the loopback port.
  * Redistribute remaining avialable 16kB space among all active ports.
  * The 10G interface should use 10kB (which is maximum possible size
                        priv->port_map |= BIT(i);
        }
 
+       if (priv->hw_version != MVPP21) {
+               if (mvpp2_read(priv, MVPP2_VER_ID_REG) == MVPP2_VER_PP23)
+                       priv->hw_version = MVPP23;
+       }
+
        /* Initialize network controller */
        err = mvpp2_init(pdev, priv);
        if (err < 0) {