summaryrefslogtreecommitdiffstats
path: root/drivers/net/fsl-fman.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/fsl-fman.c')
-rw-r--r--drivers/net/fsl-fman.c1333
1 files changed, 1333 insertions, 0 deletions
diff --git a/drivers/net/fsl-fman.c b/drivers/net/fsl-fman.c
new file mode 100644
index 0000000000..1a11ca4926
--- /dev/null
+++ b/drivers/net/fsl-fman.c
@@ -0,0 +1,1333 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc.
+ * Dave Liu <daveliu@freescale.com>
+ */
+
+#include <common.h>
+#include <io.h>
+#include <malloc.h>
+#include <net.h>
+#include <init.h>
+#include <of_net.h>
+#include <dma.h>
+#include <firmware.h>
+#include <soc/fsl/qe.h>
+#include <soc/fsl/fsl_fman.h>
+#include <soc/fsl/fsl_memac.h>
+
+/* Port ID */
+#define OH_PORT_ID_BASE 0x01
+#define MAX_NUM_OH_PORT 7
+#define RX_PORT_1G_BASE 0x08
+#define MAX_NUM_RX_PORT_1G 8
+#define RX_PORT_10G_BASE 0x10
+#define RX_PORT_10G_BASE2 0x08
+#define TX_PORT_1G_BASE 0x28
+#define MAX_NUM_TX_PORT_1G 8
+#define TX_PORT_10G_BASE 0x30
+#define TX_PORT_10G_BASE2 0x28
+#define MIIM_TIMEOUT 0xFFFF
+
+struct fm_muram {
+ void *base;
+ void *top;
+ size_t size;
+ void *alloc;
+};
+#define FM_MURAM_RES_SIZE 0x01000
+
+/* Rx/Tx buffer descriptor */
+struct fm_port_bd {
+ u16 status;
+ u16 len;
+ u32 res0;
+ u16 res1;
+ u16 buf_ptr_hi;
+ u32 buf_ptr_lo;
+};
+
+/* Common BD flags */
+#define BD_LAST 0x0800
+
+/* Rx BD status flags */
+#define RxBD_EMPTY 0x8000
+#define RxBD_LAST BD_LAST
+#define RxBD_FIRST 0x0400
+#define RxBD_PHYS_ERR 0x0008
+#define RxBD_SIZE_ERR 0x0004
+#define RxBD_ERROR (RxBD_PHYS_ERR | RxBD_SIZE_ERR)
+
+/* Tx BD status flags */
+#define TxBD_READY 0x8000
+#define TxBD_LAST BD_LAST
+
+/* Rx/Tx queue descriptor */
+struct fm_port_qd {
+ u16 gen;
+ u16 bd_ring_base_hi;
+ u32 bd_ring_base_lo;
+ u16 bd_ring_size;
+ u16 offset_in;
+ u16 offset_out;
+ u16 res0;
+ u32 res1[0x4];
+};
+
+/* IM global parameter RAM */
+struct fm_port_global_pram {
+ u32 mode; /* independent mode register */
+ u32 rxqd_ptr; /* Rx queue descriptor pointer */
+ u32 txqd_ptr; /* Tx queue descriptor pointer */
+ u16 mrblr; /* max Rx buffer length */
+ u16 rxqd_bsy_cnt; /* RxQD busy counter, should be cleared */
+ u32 res0[0x4];
+ struct fm_port_qd rxqd; /* Rx queue descriptor */
+ struct fm_port_qd txqd; /* Tx queue descriptor */
+ u32 res1[0x28];
+};
+
+#define FM_PRAM_SIZE sizeof(struct fm_port_global_pram)
+#define FM_PRAM_ALIGN 256
+#define PRAM_MODE_GLOBAL 0x20000000
+#define PRAM_MODE_GRACEFUL_STOP 0x00800000
+
+#define FM_FREE_POOL_SIZE 0x20000 /* 128K bytes */
+#define FM_FREE_POOL_ALIGN 256
+
+/* Fman ethernet private struct */
+struct fm_eth {
+ struct fm_bmi_tx_port *tx_port;
+ struct fm_bmi_rx_port *rx_port;
+ phy_interface_t enet_if;
+ struct eth_device edev;
+ struct device_d *dev;
+ struct fm_port_global_pram *rx_pram; /* Rx parameter table */
+ struct fm_port_global_pram *tx_pram; /* Tx parameter table */
+ void *rx_bd_ring; /* Rx BD ring base */
+ void *cur_rxbd; /* current Rx BD */
+ void *rx_buf; /* Rx buffer base */
+ void *tx_bd_ring; /* Tx BD ring base */
+ void *cur_txbd; /* current Tx BD */
+ struct memac *regs;
+};
+
+#define RX_BD_RING_SIZE 8
+#define TX_BD_RING_SIZE 8
+#define MAX_RXBUF_LOG2 11
+#define MAX_RXBUF_LEN (1 << MAX_RXBUF_LOG2)
+
+struct fsl_fman_mdio {
+ struct mii_bus bus;
+ struct memac_mdio_controller *regs;
+};
+
+enum fman_port_type {
+ FMAN_PORT_TYPE_RX = 0, /* RX Port */
+ FMAN_PORT_TYPE_TX, /* TX Port */
+};
+
+struct fsl_fman_port {
+ void *regs;
+ enum fman_port_type type;
+ struct fm_bmi_rx_port *rxport;
+ struct fm_bmi_tx_port *txport;
+};
+
+static struct fm_eth *to_fm_eth(struct eth_device *edev)
+{
+ return container_of(edev, struct fm_eth, edev);
+}
+
+static struct fm_muram muram;
+
+static void *fm_muram_base(void)
+{
+ return muram.base;
+}
+
+static void *fm_muram_alloc(size_t size, unsigned long align)
+{
+ void *ret;
+ unsigned long align_mask;
+ size_t off;
+ void *save;
+
+ align_mask = align - 1;
+ save = muram.alloc;
+
+ off = (unsigned long)save & align_mask;
+ if (off != 0)
+ muram.alloc += (align - off);
+ off = size & align_mask;
+ if (off != 0)
+ size += (align - off);
+ if ((muram.alloc + size) >= muram.top) {
+ muram.alloc = save;
+ printf("%s: run out of ram.\n", __func__);
+ return NULL;
+ }
+
+ ret = muram.alloc;
+ muram.alloc += size;
+
+ return ret;
+}
+
+/*
+ * fm_upload_ucode - Fman microcode upload worker function
+ *
+ * This function does the actual uploading of an Fman microcode
+ * to an Fman.
+ */
+static int fm_upload_ucode(struct fm_imem *imem,
+ u32 *ucode, unsigned int size)
+{
+ unsigned int i;
+ unsigned int timeout = 1000000;
+
+ /* enable address auto increase */
+ out_be32(&imem->iadd, IRAM_IADD_AIE);
+ /* write microcode to IRAM */
+ for (i = 0; i < size / 4; i++)
+ out_be32(&imem->idata, (be32_to_cpu(ucode[i])));
+
+ /* verify if the writing is over */
+ out_be32(&imem->iadd, 0);
+ while ((in_be32(&imem->idata) != be32_to_cpu(ucode[0])) && --timeout)
+ ;
+ if (!timeout) {
+ printf("microcode upload timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ /* enable microcode from IRAM */
+ out_be32(&imem->iready, IRAM_READY);
+
+ return 0;
+}
+
+static int fman_upload_firmware(struct device_d *dev, struct fm_imem *fm_imem)
+{
+ int i, size, ret;
+ const struct qe_firmware *firmware;
+
+ get_builtin_firmware(fsl_fman_ucode_ls1046_r1_0_106_4_18_bin, &firmware, &size);
+
+ ret = qe_validate_firmware(firmware, size);
+ if (ret)
+ return ret;
+
+ if (firmware->count != 1) {
+ dev_err(dev, "Invalid data in firmware header\n");
+ return -EINVAL;
+ }
+
+ /* Loop through each microcode. */
+ for (i = 0; i < firmware->count; i++) {
+ const struct qe_microcode *ucode = &firmware->microcode[i];
+
+ /* Upload a microcode if it's present */
+ if (be32_to_cpu(ucode->code_offset)) {
+ u32 ucode_size;
+ u32 *code;
+ dev_info(dev, "Uploading microcode version %u.%u.%u\n",
+ ucode->major, ucode->minor,
+ ucode->revision);
+ code = (void *)firmware +
+ be32_to_cpu(ucode->code_offset);
+ ucode_size = sizeof(u32) * be32_to_cpu(ucode->count);
+ ret = fm_upload_ucode(fm_imem, code, ucode_size);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static u32 fm_assign_risc(int port_id)
+{
+ u32 risc_sel, val;
+ risc_sel = (port_id & 0x1) ? FMFPPRC_RISC2 : FMFPPRC_RISC1;
+ val = (port_id << FMFPPRC_PORTID_SHIFT) & FMFPPRC_PORTID_MASK;
+ val |= ((risc_sel << FMFPPRC_ORA_SHIFT) | risc_sel);
+
+ return val;
+}
+
+static void fm_init_fpm(struct fm_fpm *fpm)
+{
+ int i, port_id;
+ u32 val;
+
+ setbits_be32(&fpm->fmfpee, FMFPEE_EHM | FMFPEE_UEC |
+ FMFPEE_CER | FMFPEE_DER);
+
+ /* IM mode, each even port ID to RISC#1, each odd port ID to RISC#2 */
+
+ /* offline/parser port */
+ for (i = 0; i < MAX_NUM_OH_PORT; i++) {
+ port_id = OH_PORT_ID_BASE + i;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+ }
+ /* Rx 1G port */
+ for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
+ port_id = RX_PORT_1G_BASE + i;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+ }
+ /* Tx 1G port */
+ for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
+ port_id = TX_PORT_1G_BASE + i;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+ }
+ /* Rx 10G port */
+ port_id = RX_PORT_10G_BASE;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+ /* Tx 10G port */
+ port_id = TX_PORT_10G_BASE;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+
+ /* disable the dispatch limit in IM case */
+ out_be32(&fpm->fpmflc, FMFP_FLC_DISP_LIM_NONE);
+ /* clear events */
+ out_be32(&fpm->fmfpee, FMFPEE_CLEAR_EVENT);
+
+ /* clear risc events */
+ for (i = 0; i < 4; i++)
+ out_be32(&fpm->fpmcev[i], 0xffffffff);
+
+ /* clear error */
+ out_be32(&fpm->fpmrcr, FMFP_RCR_MDEC | FMFP_RCR_IDEC);
+}
+
+static int fm_init_bmi(struct fm_bmi_common *bmi)
+{
+ int blk, i, port_id;
+ u32 val;
+ size_t offset;
+ void *base;
+
+ /* alloc free buffer pool in MURAM */
+ base = fm_muram_alloc(FM_FREE_POOL_SIZE, FM_FREE_POOL_ALIGN);
+ if (!base) {
+ printf("%s: no muram for free buffer pool\n", __func__);
+ return -ENOMEM;
+ }
+ offset = base - fm_muram_base();
+
+ /* Need 128KB total free buffer pool size */
+ val = offset / 256;
+ blk = FM_FREE_POOL_SIZE / 256;
+ /* in IM, we must not begin from offset 0 in MURAM */
+ val |= ((blk - 1) << FMBM_CFG1_FBPS_SHIFT);
+ out_be32(&bmi->fmbm_cfg1, val);
+
+ /* disable all BMI interrupt */
+ out_be32(&bmi->fmbm_ier, FMBM_IER_DISABLE_ALL);
+
+ /* clear all events */
+ out_be32(&bmi->fmbm_ievr, FMBM_IEVR_CLEAR_ALL);
+
+ /*
+ * set port parameters - FMBM_PP_x
+ * max tasks 10G Rx/Tx=12, 1G Rx/Tx 4, others is 1
+ * max dma 10G Rx/Tx=3, others is 1
+ * set port FIFO size - FMBM_PFS_x
+ * 4KB for all Rx and Tx ports
+ */
+ /* offline/parser port */
+ for (i = 0; i < MAX_NUM_OH_PORT; i++) {
+ port_id = OH_PORT_ID_BASE + i - 1;
+ /* max tasks=1, max dma=1, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], 0);
+ /* port FIFO size - 256 bytes, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], 0);
+ }
+ /* Rx 1G port */
+ for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
+ port_id = RX_PORT_1G_BASE + i - 1;
+ /* max tasks=4, max dma=1, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
+ /* FIFO size - 4KB, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
+ }
+ /* Tx 1G port FIFO size - 4KB, no extra */
+ for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
+ port_id = TX_PORT_1G_BASE + i - 1;
+ /* max tasks=4, max dma=1, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
+ /* FIFO size - 4KB, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
+ }
+ /* Rx 10G port */
+ port_id = RX_PORT_10G_BASE - 1;
+ /* max tasks=12, max dma=3, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
+ /* FIFO size - 4KB, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
+
+ /* Tx 10G port */
+ port_id = TX_PORT_10G_BASE - 1;
+ /* max tasks=12, max dma=3, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
+ /* FIFO size - 4KB, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
+
+ /* initialize internal buffers data base (linked list) */
+ out_be32(&bmi->fmbm_init, FMBM_INIT_START);
+
+ return 0;
+}
+
+static void fm_init_qmi(struct fm_qmi_common *qmi)
+{
+ /* disable all error interrupts */
+ out_be32(&qmi->fmqm_eien, FMQM_EIEN_DISABLE_ALL);
+ /* clear all error events */
+ out_be32(&qmi->fmqm_eie, FMQM_EIE_CLEAR_ALL);
+
+ /* disable all interrupts */
+ out_be32(&qmi->fmqm_ien, FMQM_IEN_DISABLE_ALL);
+ /* clear all interrupts */
+ out_be32(&qmi->fmqm_ie, FMQM_IE_CLEAR_ALL);
+}
+
+static int fm_init_common(struct device_d *dev, struct ccsr_fman *reg)
+{
+ int ret;
+
+ /* Upload the Fman microcode if it's present */
+ ret = fman_upload_firmware(dev, &reg->fm_imem);
+ if (ret)
+ return ret;
+
+ fm_init_qmi(&reg->fm_qmi_common);
+ fm_init_fpm(&reg->fm_fpm);
+
+ /* clear DMA status */
+ setbits_be32(&reg->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL);
+
+ /* set DMA mode */
+ setbits_be32(&reg->fm_dma.fmdmmr, FMDMMR_SBER);
+
+ return fm_init_bmi(&reg->fm_bmi_common);
+}
+
+#define memac_out_32(a, v) out_be32(a, v)
+#define memac_in_32(a) in_be32(a)
+#define memac_clrbits_32(a, v) clrbits_be32(a, v)
+#define memac_setbits_32(a, v) setbits_be32(a, v)
+
+static int memac_mdio_write(struct mii_bus *bus, int port_addr, int regnum, u16 value)
+{
+ struct fsl_fman_mdio *priv = container_of(bus, struct fsl_fman_mdio, bus);
+ struct memac_mdio_controller *regs = priv->regs;
+ u32 mdio_ctl;
+
+ memac_clrbits_32(&regs->mdio_stat, MDIO_STAT_ENC);
+
+ /* Wait till the bus is free */
+ while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Set the port and dev addr */
+ mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(regnum);
+ memac_out_32(&regs->mdio_ctl, mdio_ctl);
+
+ /* Wait till the bus is free */
+ while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Write the value to the register */
+ memac_out_32(&regs->mdio_data, MDIO_DATA(value));
+
+ /* Wait till the MDIO write is complete */
+ while ((memac_in_32(&regs->mdio_data)) & MDIO_DATA_BSY)
+ ;
+
+ return 0;
+}
+
+static int memac_mdio_read(struct mii_bus *bus, int port_addr, int regnum)
+{
+ struct fsl_fman_mdio *priv = container_of(bus, struct fsl_fman_mdio, bus);
+ struct memac_mdio_controller *regs = priv->regs;
+ u32 mdio_ctl;
+
+ memac_clrbits_32(&regs->mdio_stat, MDIO_STAT_ENC);
+
+ /* Wait till the bus is free */
+ while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Set the Port and Device Addrs */
+ mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(regnum);
+ memac_out_32(&regs->mdio_ctl, mdio_ctl);
+
+ /* Wait till the bus is free */
+ while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Initiate the read */
+ mdio_ctl |= MDIO_CTL_READ;
+ memac_out_32(&regs->mdio_ctl, mdio_ctl);
+
+ /* Wait till the MDIO write is complete */
+ while ((memac_in_32(&regs->mdio_data)) & MDIO_DATA_BSY)
+ ;
+
+ /* Return all Fs if nothing was there */
+ if (memac_in_32(&regs->mdio_stat) & MDIO_STAT_RD_ER)
+ return 0xffff;
+
+ return memac_in_32(&regs->mdio_data) & 0xffff;
+}
+
+static u16 muram_readw(u16 *addr)
+{
+ unsigned long base = (unsigned long)addr & ~0x3UL;
+ u32 val32 = in_be32((void *)base);
+ int byte_pos;
+ u16 ret;
+
+ byte_pos = (unsigned long)addr & 0x3UL;
+ if (byte_pos)
+ ret = (u16)(val32 & 0x0000ffff);
+ else
+ ret = (u16)((val32 & 0xffff0000) >> 16);
+
+ return ret;
+}
+
+static void muram_writew(u16 *addr, u16 val)
+{
+ unsigned long base = (unsigned long)addr & ~0x3UL;
+ u32 org32 = in_be32((void *)base);
+ u32 val32;
+ int byte_pos;
+
+ byte_pos = (unsigned long)addr & 0x3UL;
+ if (byte_pos)
+ val32 = (org32 & 0xffff0000) | val;
+ else
+ val32 = (org32 & 0x0000ffff) | ((u32)val << 16);
+
+ out_be32((void *)base, val32);
+}
+
+static void bmi_rx_port_disable(struct fm_bmi_rx_port *rx_port)
+{
+ int timeout = 1000000;
+
+ clrbits_be32(&rx_port->fmbm_rcfg, FMBM_RCFG_EN);
+
+ /* wait until the rx port is not busy */
+ while ((in_be32(&rx_port->fmbm_rst) & FMBM_RST_BSY) && timeout--)
+ ;
+}
+
+static void bmi_rx_port_init(struct fm_bmi_rx_port *rx_port)
+{
+ /* set BMI to independent mode, Rx port disable */
+ out_be32(&rx_port->fmbm_rcfg, FMBM_RCFG_IM);
+ /* clear FOF in IM case */
+ out_be32(&rx_port->fmbm_rim, 0);
+ /* Rx frame next engine -RISC */
+ out_be32(&rx_port->fmbm_rfne, NIA_ENG_RISC | NIA_RISC_AC_IM_RX);
+ /* Rx command attribute - no order, MR[3] = 1 */
+ clrbits_be32(&rx_port->fmbm_rfca, FMBM_RFCA_ORDER | FMBM_RFCA_MR_MASK);
+ setbits_be32(&rx_port->fmbm_rfca, FMBM_RFCA_MR(4));
+ /* enable Rx statistic counters */
+ out_be32(&rx_port->fmbm_rstc, FMBM_RSTC_EN);
+ /* disable Rx performance counters */
+ out_be32(&rx_port->fmbm_rpc, 0);
+}
+
+static void bmi_tx_port_disable(struct fm_bmi_tx_port *tx_port)
+{
+ int timeout = 1000000;
+
+ clrbits_be32(&tx_port->fmbm_tcfg, FMBM_TCFG_EN);
+
+ /* wait until the tx port is not busy */
+ while ((in_be32(&tx_port->fmbm_tst) & FMBM_TST_BSY) && timeout--)
+ ;
+}
+
+static void bmi_tx_port_init(struct fm_bmi_tx_port *tx_port)
+{
+ /* set BMI to independent mode, Tx port disable */
+ out_be32(&tx_port->fmbm_tcfg, FMBM_TCFG_IM);
+ /* Tx frame next engine -RISC */
+ out_be32(&tx_port->fmbm_tfne, NIA_ENG_RISC | NIA_RISC_AC_IM_TX);
+ out_be32(&tx_port->fmbm_tfene, NIA_ENG_RISC | NIA_RISC_AC_IM_TX);
+ /* Tx command attribute - no order, MR[3] = 1 */
+ clrbits_be32(&tx_port->fmbm_tfca, FMBM_TFCA_ORDER | FMBM_TFCA_MR_MASK);
+ setbits_be32(&tx_port->fmbm_tfca, FMBM_TFCA_MR(4));
+ /* enable Tx statistic counters */
+ out_be32(&tx_port->fmbm_tstc, FMBM_TSTC_EN);
+ /* disable Tx performance counters */
+ out_be32(&tx_port->fmbm_tpc, 0);
+}
+
+static int fm_eth_rx_port_parameter_init(struct fm_eth *fm_eth)
+{
+ struct fm_port_global_pram *pram;
+ u32 pram_page_offset;
+ void *rx_bd_ring_base;
+ void *rx_buf_pool;
+ u32 bd_ring_base_lo, bd_ring_base_hi;
+ u32 buf_lo, buf_hi;
+ struct fm_port_bd *rxbd;
+ struct fm_port_qd *rxqd;
+ struct fm_bmi_rx_port *bmi_rx_port = fm_eth->rx_port;
+ int i;
+
+ /* alloc global parameter ram at MURAM */
+ pram = fm_muram_alloc(FM_PRAM_SIZE, FM_PRAM_ALIGN);
+ if (!pram) {
+ printf("%s: No muram for Rx global parameter\n", __func__);
+ return -ENOMEM;
+ }
+
+ fm_eth->rx_pram = pram;
+
+ /* parameter page offset to MURAM */
+ pram_page_offset = (void *)pram - fm_muram_base();
+
+ /* enable global mode- snooping data buffers and BDs */
+ out_be32(&pram->mode, PRAM_MODE_GLOBAL);
+
+ /* init the Rx queue descriptor pointer */
+ out_be32(&pram->rxqd_ptr, pram_page_offset + 0x20);
+
+ /* set the max receive buffer length, power of 2 */
+ muram_writew(&pram->mrblr, MAX_RXBUF_LOG2);
+
+ /* alloc Rx buffer descriptors from main memory */
+ rx_bd_ring_base = dma_alloc_coherent(sizeof(struct fm_port_bd)
+ * RX_BD_RING_SIZE, DMA_ADDRESS_BROKEN);
+ if (!rx_bd_ring_base)
+ return -ENOMEM;
+
+ memset(rx_bd_ring_base, 0, sizeof(struct fm_port_bd)
+ * RX_BD_RING_SIZE);
+
+ /* alloc Rx buffer from main memory */
+ rx_buf_pool = malloc(MAX_RXBUF_LEN * RX_BD_RING_SIZE);
+ if (!rx_buf_pool)
+ return -ENOMEM;
+
+ memset(rx_buf_pool, 0, MAX_RXBUF_LEN * RX_BD_RING_SIZE);
+
+ /* save them to fm_eth */
+ fm_eth->rx_bd_ring = rx_bd_ring_base;
+ fm_eth->cur_rxbd = rx_bd_ring_base;
+ fm_eth->rx_buf = rx_buf_pool;
+
+ /* init Rx BDs ring */
+ rxbd = rx_bd_ring_base;
+ for (i = 0; i < RX_BD_RING_SIZE; i++) {
+ muram_writew(&rxbd->status, RxBD_EMPTY);
+ muram_writew(&rxbd->len, 0);
+ buf_hi = upper_32_bits(virt_to_phys(rx_buf_pool +
+ i * MAX_RXBUF_LEN));
+ buf_lo = lower_32_bits(virt_to_phys(rx_buf_pool +
+ i * MAX_RXBUF_LEN));
+ muram_writew(&rxbd->buf_ptr_hi, (u16)buf_hi);
+ out_be32(&rxbd->buf_ptr_lo, buf_lo);
+ rxbd++;
+ }
+
+ /* set the Rx queue descriptor */
+ rxqd = &pram->rxqd;
+ muram_writew(&rxqd->gen, 0);
+ bd_ring_base_hi = upper_32_bits(virt_to_phys(rx_bd_ring_base));
+ bd_ring_base_lo = lower_32_bits(virt_to_phys(rx_bd_ring_base));
+ muram_writew(&rxqd->bd_ring_base_hi, (u16)bd_ring_base_hi);
+ out_be32(&rxqd->bd_ring_base_lo, bd_ring_base_lo);
+ muram_writew(&rxqd->bd_ring_size, sizeof(struct fm_port_bd)
+ * RX_BD_RING_SIZE);
+ muram_writew(&rxqd->offset_in, 0);
+ muram_writew(&rxqd->offset_out, 0);
+
+ /* set IM parameter ram pointer to Rx Frame Queue ID */
+ out_be32(&bmi_rx_port->fmbm_rfqid, pram_page_offset);
+
+ return 0;
+}
+
+static int fm_eth_tx_port_parameter_init(struct fm_eth *fm_eth)
+{
+ struct fm_port_global_pram *pram;
+ u32 pram_page_offset;
+ void *tx_bd_ring_base;
+ u32 bd_ring_base_lo, bd_ring_base_hi;
+ struct fm_port_bd *txbd;
+ struct fm_port_qd *txqd;
+ struct fm_bmi_tx_port *bmi_tx_port = fm_eth->tx_port;
+ int i;
+
+ /* alloc global parameter ram at MURAM */
+ pram = fm_muram_alloc(FM_PRAM_SIZE, FM_PRAM_ALIGN);
+ if (!pram)
+ return -ENOMEM;
+
+ fm_eth->tx_pram = pram;
+
+ /* parameter page offset to MURAM */
+ pram_page_offset = (void *)pram - fm_muram_base();
+
+ /* enable global mode- snooping data buffers and BDs */
+ out_be32(&pram->mode, PRAM_MODE_GLOBAL);
+
+ /* init the Tx queue descriptor pionter */
+ out_be32(&pram->txqd_ptr, pram_page_offset + 0x40);
+
+ /* alloc Tx buffer descriptors from main memory */
+ tx_bd_ring_base = dma_alloc_coherent(sizeof(struct fm_port_bd)
+ * TX_BD_RING_SIZE, DMA_ADDRESS_BROKEN);
+ if (!tx_bd_ring_base)
+ return -ENOMEM;
+
+ memset(tx_bd_ring_base, 0, sizeof(struct fm_port_bd)
+ * TX_BD_RING_SIZE);
+ /* save it to fm_eth */
+ fm_eth->tx_bd_ring = tx_bd_ring_base;
+ fm_eth->cur_txbd = tx_bd_ring_base;
+
+ /* init Tx BDs ring */
+ txbd = tx_bd_ring_base;
+ for (i = 0; i < TX_BD_RING_SIZE; i++) {
+ muram_writew(&txbd->status, TxBD_LAST);
+ muram_writew(&txbd->len, 0);
+ muram_writew(&txbd->buf_ptr_hi, 0);
+ out_be32(&txbd->buf_ptr_lo, 0);
+ txbd++;
+ }
+
+ /* set the Tx queue decriptor */
+ txqd = &pram->txqd;
+ bd_ring_base_hi = upper_32_bits(virt_to_phys(tx_bd_ring_base));
+ bd_ring_base_lo = lower_32_bits(virt_to_phys(tx_bd_ring_base));
+ muram_writew(&txqd->bd_ring_base_hi, (u16)bd_ring_base_hi);
+ out_be32(&txqd->bd_ring_base_lo, bd_ring_base_lo);
+ muram_writew(&txqd->bd_ring_size, sizeof(struct fm_port_bd)
+ * TX_BD_RING_SIZE);
+ muram_writew(&txqd->offset_in, 0);
+ muram_writew(&txqd->offset_out, 0);
+
+ /* set IM parameter ram pointer to Tx Confirmation Frame Queue ID */
+ out_be32(&bmi_tx_port->fmbm_tcfqid, pram_page_offset);
+
+ return 0;
+}
+
+static void fmc_tx_port_graceful_stop_enable(struct fm_eth *fm_eth)
+{
+ struct fm_port_global_pram *pram;
+
+ pram = fm_eth->tx_pram;
+ /* graceful stop transmission of frames */
+ setbits_be32(&pram->mode, PRAM_MODE_GRACEFUL_STOP);
+}
+
+static void fmc_tx_port_graceful_stop_disable(struct fm_eth *fm_eth)
+{
+ struct fm_port_global_pram *pram;
+
+ pram = fm_eth->tx_pram;
+ /* re-enable transmission of frames */
+ clrbits_be32(&pram->mode, PRAM_MODE_GRACEFUL_STOP);
+}
+
+static void memac_adjust_link_speed(struct eth_device *edev)
+{
+ struct fm_eth *fm_eth = to_fm_eth(edev);
+ struct memac *regs = fm_eth->regs;
+ int speed = edev->phydev->speed;
+ u32 if_mode;
+ phy_interface_t type = fm_eth->enet_if;
+
+ if_mode = in_be32(&regs->if_mode);
+
+ if (type == PHY_INTERFACE_MODE_RGMII ||
+ type == PHY_INTERFACE_MODE_RGMII_ID ||
+ type == PHY_INTERFACE_MODE_RGMII_TXID) {
+ if_mode &= ~IF_MODE_EN_AUTO;
+ if_mode &= ~IF_MODE_SETSP_MASK;
+
+ switch (speed) {
+ case SPEED_1000:
+ if_mode |= IF_MODE_SETSP_1000M;
+ break;
+ case SPEED_100:
+ if_mode |= IF_MODE_SETSP_100M;
+ break;
+ case SPEED_10:
+ if_mode |= IF_MODE_SETSP_10M;
+ default:
+ break;
+ }
+ }
+
+ out_be32(&regs->if_mode, if_mode);
+
+ return;
+}
+
+static int fm_eth_open(struct eth_device *edev)
+{
+ struct fm_eth *fm_eth = to_fm_eth(edev);
+ struct memac *regs = fm_eth->regs;
+ int ret;
+
+ ret = phy_device_connect(edev, NULL, -1, memac_adjust_link_speed, 0,
+ fm_eth->enet_if);
+ if (ret)
+ return ret;
+
+ /* enable bmi Rx port */
+ setbits_be32(&fm_eth->rx_port->fmbm_rcfg, FMBM_RCFG_EN);
+ /* enable MAC rx/tx port */
+ setbits_be32(&regs->command_config,
+ MEMAC_CMD_CFG_RXTX_EN | MEMAC_CMD_CFG_NO_LEN_CHK);
+
+ /* enable bmi Tx port */
+ setbits_be32(&fm_eth->tx_port->fmbm_tcfg, FMBM_TCFG_EN);
+ /* re-enable transmission of frame */
+ fmc_tx_port_graceful_stop_disable(fm_eth);
+
+ return 0;
+}
+
+static void memac_disable_mac(struct fm_eth *fm_eth)
+{
+ struct memac *regs = fm_eth->regs;
+
+ clrbits_be32(&regs->command_config, MEMAC_CMD_CFG_RXTX_EN);
+}
+
+static void fm_eth_halt(struct eth_device *edev)
+{
+ struct fm_eth *fm_eth = to_fm_eth(edev);
+
+ /* graceful stop the transmission of frames */
+ fmc_tx_port_graceful_stop_enable(fm_eth);
+ /* disable bmi Tx port */
+ bmi_tx_port_disable(fm_eth->tx_port);
+ /* disable MAC rx/tx port */
+ memac_disable_mac(fm_eth);
+ /* disable bmi Rx port */
+ bmi_rx_port_disable(fm_eth->rx_port);
+}
+
+static int fm_eth_send(struct eth_device *edev, void *buf, int len)
+{
+ struct fm_eth *fm_eth = to_fm_eth(edev);
+ struct fm_port_global_pram *pram;
+ struct fm_port_bd *txbd, *txbd_base;
+ u16 offset_in;
+ int i;
+ dma_addr_t dma;
+
+ pram = fm_eth->tx_pram;
+ txbd = fm_eth->cur_txbd;
+
+ /* find one empty TxBD */
+ for (i = 0; muram_readw(&txbd->status) & TxBD_READY; i++) {
+ udelay(100);
+ if (i > 0x1000) {
+ dev_err(&edev->dev, "Tx buffer not ready, txbd->status = 0x%x\n",
+ muram_readw(&txbd->status));
+ return -EIO;
+ }
+ }
+
+ dma = dma_map_single(fm_eth->dev, buf, len, DMA_TO_DEVICE);
+ if (dma_mapping_error(fm_eth->dev, dma))
+ return -EFAULT;
+
+ /* setup TxBD */
+ muram_writew(&txbd->buf_ptr_hi, (u16)upper_32_bits(dma));
+ out_be32(&txbd->buf_ptr_lo, lower_32_bits(dma));
+ muram_writew(&txbd->len, len);
+ muram_writew(&txbd->status, TxBD_READY | TxBD_LAST);
+
+ /* update TxQD, let RISC to send the packet */
+ offset_in = muram_readw(&pram->txqd.offset_in);
+ offset_in += sizeof(struct fm_port_bd);
+ if (offset_in >= muram_readw(&pram->txqd.bd_ring_size))
+ offset_in = 0;
+ muram_writew(&pram->txqd.offset_in, offset_in);
+
+ /* wait for buffer to be transmitted */
+ for (i = 0; muram_readw(&txbd->status) & TxBD_READY; i++) {
+ udelay(10);
+ if (i > 0x10000) {
+ dev_err(&edev->dev, "Tx error, txbd->status = 0x%x\n",
+ muram_readw(&txbd->status));
+ return -EIO;
+ }
+ }
+
+ dma_unmap_single(fm_eth->dev, dma, len, DMA_TO_DEVICE);
+
+ /* advance the TxBD */
+ txbd++;
+ txbd_base = fm_eth->tx_bd_ring;
+ if (txbd >= (txbd_base + TX_BD_RING_SIZE))
+ txbd = txbd_base;
+ /* update current txbd */
+ fm_eth->cur_txbd = (void *)txbd;
+
+ return 0;
+}
+
+static int fm_eth_recv(struct eth_device *edev)
+{
+ struct fm_eth *fm_eth = to_fm_eth(edev);
+ struct fm_port_global_pram *pram;
+ struct fm_port_bd *rxbd, *rxbd_base;
+ u16 status, len;
+ u32 buf_lo, buf_hi;
+ u8 *data;
+ u16 offset_out;
+ int ret = 1;
+
+ pram = fm_eth->rx_pram;
+ rxbd = fm_eth->cur_rxbd;
+ status = muram_readw(&rxbd->status);
+
+ while (!(status & RxBD_EMPTY)) {
+ if (!(status & RxBD_ERROR)) {
+ buf_hi = muram_readw(&rxbd->buf_ptr_hi);
+ buf_lo = in_be32(&rxbd->buf_ptr_lo);
+ data = (u8 *)((unsigned long)(buf_hi << 16) << 16 | buf_lo);
+ len = muram_readw(&rxbd->len);
+
+ dma_sync_single_for_cpu((unsigned long)data,
+ len,
+ DMA_FROM_DEVICE);
+
+ net_receive(edev, data, len);
+
+ dma_sync_single_for_device((unsigned long)data,
+ len,
+ DMA_FROM_DEVICE);
+ } else {
+ dev_err(&edev->dev, "Rx error\n");
+ ret = 0;
+ }
+
+ /* clear the RxBDs */
+ muram_writew(&rxbd->status, RxBD_EMPTY);
+ muram_writew(&rxbd->len, 0);
+
+ /* advance RxBD */
+ rxbd++;
+ rxbd_base = fm_eth->rx_bd_ring;
+ if (rxbd >= (rxbd_base + RX_BD_RING_SIZE))
+ rxbd = rxbd_base;
+ /* read next status */
+ status = muram_readw(&rxbd->status);
+
+ /* update RxQD */
+ offset_out = muram_readw(&pram->rxqd.offset_out);
+ offset_out += sizeof(struct fm_port_bd);
+ if (offset_out >= muram_readw(&pram->rxqd.bd_ring_size))
+ offset_out = 0;
+ muram_writew(&pram->rxqd.offset_out, offset_out);
+ }
+ fm_eth->cur_rxbd = rxbd;
+
+ return ret;
+}
+
+static void memac_init_mac(struct fm_eth *fm_eth)
+{
+ struct memac *regs = fm_eth->regs;
+
+ /* mask all interrupt */
+ out_be32(&regs->imask, IMASK_MASK_ALL);
+
+ /* clear all events */
+ out_be32(&regs->ievent, IEVENT_CLEAR_ALL);
+
+ /* set the max receive length */
+ out_be32(&regs->maxfrm, MAX_RXBUF_LEN);
+
+ /* multicast frame reception for the hash entry disable */
+ out_be32(&regs->hashtable_ctrl, 0);
+}
+
+static int memac_set_ethaddr(struct eth_device *edev, const unsigned char *adr)
+{
+ struct fm_eth *fm_eth = to_fm_eth(edev);
+ struct memac *regs = fm_eth->regs;
+ u32 mac_addr0, mac_addr1;
+
+ /*
+ * if a station address of 0x12345678ABCD, perform a write to
+ * MAC_ADDR0 of 0x78563412, MAC_ADDR1 of 0x0000CDAB
+ */
+ mac_addr0 = (adr[3] << 24) | (adr[2] << 16) | \
+ (adr[1] << 8) | (adr[0]);
+ out_be32(&regs->mac_addr_0, mac_addr0);
+
+ mac_addr1 = ((adr[5] << 8) | adr[4]) & 0x0000ffff;
+ out_be32(&regs->mac_addr_1, mac_addr1);
+
+ return 0;
+}
+
+static int memac_get_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+ struct fm_eth *fm_eth = to_fm_eth(edev);
+ struct memac *regs = fm_eth->regs;
+ u32 mac_addr0, mac_addr1;
+
+ mac_addr0 = in_be32(&regs->mac_addr_0);
+ mac_addr1 = in_be32(&regs->mac_addr_1);
+
+ adr[0] = mac_addr0 & 0xff;
+ adr[1] = (mac_addr0 >> 8) & 0xff;
+ adr[2] = (mac_addr0 >> 16) & 0xff;
+ adr[3] = (mac_addr0 >> 24) & 0xff;
+ adr[4] = mac_addr1 & 0xff;
+ adr[5] = (mac_addr1 >> 8) & 0xff;
+
+ return 0;
+}
+
+static void memac_set_interface_mode(struct fm_eth *fm_eth,
+ phy_interface_t type)
+{
+ struct memac *regs = fm_eth->regs;
+ u32 if_mode;
+
+ /* clear all bits relative with interface mode */
+ if_mode = in_be32(&regs->if_mode) & ~IF_MODE_MASK;
+
+ /* set interface mode */
+ switch (type) {
+ case PHY_INTERFACE_MODE_GMII:
+ if_mode |= IF_MODE_GMII | IF_MODE_EN_AUTO;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if_mode |= IF_MODE_GMII | IF_MODE_RG | IF_MODE_EN_AUTO;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ if_mode |= IF_MODE_GMII | IF_MODE_EN_AUTO;
+ break;
+ case PHY_INTERFACE_MODE_XGMII:
+ if_mode |= IF_MODE_XGMII;
+ break;
+ default:
+ break;
+ }
+
+ out_be32(&regs->if_mode, if_mode);
+}
+
+static int fm_eth_startup(struct fm_eth *fm_eth)
+{
+ int ret;
+
+ ret = fm_eth_rx_port_parameter_init(fm_eth);
+ if (ret)
+ return ret;
+
+ ret = fm_eth_tx_port_parameter_init(fm_eth);
+ if (ret)
+ return ret;
+
+ /* setup the MAC controller */
+ memac_init_mac(fm_eth);
+
+ /* init bmi rx port, IM mode and disable */
+ bmi_rx_port_init(fm_eth->rx_port);
+
+ /* init bmi tx port, IM mode and disable */
+ bmi_tx_port_init(fm_eth->tx_port);
+
+ memac_set_interface_mode(fm_eth, fm_eth->enet_if);
+
+ return 0;
+}
+
+static int fsl_fman_mdio_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ int ret;
+ struct fsl_fman_mdio *priv;
+
+ dev_dbg(dev, "probe\n");
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ priv = xzalloc(sizeof(*priv));
+
+ priv->bus.read = memac_mdio_read;
+ priv->bus.write = memac_mdio_write;
+ priv->bus.parent = dev;
+ priv->regs = IOMEM(iores->start);
+
+ memac_setbits_32(&priv->regs->mdio_stat,
+ MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG);
+
+ ret = mdiobus_register(&priv->bus);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int fsl_fman_port_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ int ret;
+ struct fsl_fman_port *port;
+ unsigned long type;
+
+ dev_dbg(dev, "probe\n");
+
+ ret = dev_get_drvdata(dev, (const void **)&type);
+ if (ret)
+ return ret;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ port = xzalloc(sizeof(*port));
+
+ port->regs = IOMEM(iores->start);
+ port->type = type;
+
+ if (type == FMAN_PORT_TYPE_RX)
+ port->rxport = port->regs;
+ else
+ port->txport = port->regs;
+
+ dev->priv = port;
+
+ return 0;
+}
+
+static int fsl_fman_memac_port_bind(struct fm_eth *fm_eth, enum fman_port_type type)
+{
+ struct device_node *macnp = fm_eth->dev->device_node;
+ struct device_node *portnp;
+ struct device_d *portdev;
+ struct fsl_fman_port *port;
+
+ portnp = of_parse_phandle(macnp, "fsl,fman-ports", type);
+ if (!portnp) {
+ dev_err(fm_eth->dev, "of_parse_phandle(%s, fsl,fman-ports) failed\n",
+ macnp->full_name);
+ return -EINVAL;
+ }
+
+ portdev = of_find_device_by_node(portnp);
+ if (!portdev)
+ return -ENOENT;
+
+ port = portdev->priv;
+ if (!port)
+ return -EINVAL;
+
+ if (type == FMAN_PORT_TYPE_TX)
+ fm_eth->tx_port = port->txport;
+ else
+ fm_eth->rx_port = port->rxport;
+
+ return 0;
+}
+
+static int fsl_fman_memac_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ struct fm_eth *fm_eth;
+ struct eth_device *edev;
+ int ret;
+ int phy_mode;
+
+ dev_dbg(dev, "probe\n");
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ /* alloc the FMan ethernet private struct */
+ fm_eth = xzalloc(sizeof(*fm_eth));
+
+ fm_eth->dev = dev;
+
+ ret = fsl_fman_memac_port_bind(fm_eth, FMAN_PORT_TYPE_TX);
+ if (ret)
+ return ret;
+
+ ret = fsl_fman_memac_port_bind(fm_eth, FMAN_PORT_TYPE_RX);
+ if (ret)
+ return ret;
+
+ phy_mode = of_get_phy_mode(dev->device_node);
+ if (phy_mode < 0)
+ return phy_mode;
+
+ fm_eth->enet_if = phy_mode;
+
+ fm_eth->regs = IOMEM(iores->start);
+
+ dev->priv = fm_eth;
+
+ edev = &fm_eth->edev;
+ edev->open = fm_eth_open;
+ edev->halt = fm_eth_halt;
+ edev->send = fm_eth_send;
+ edev->recv = fm_eth_recv;
+ edev->get_ethaddr = memac_get_ethaddr;
+ edev->set_ethaddr = memac_set_ethaddr;
+ edev->parent = dev;
+
+ /* startup the FM im */
+ ret = fm_eth_startup(fm_eth);
+ if (ret)
+ return ret;
+
+ ret = eth_register(edev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int fsl_fman_muram_probe(struct device_d *dev)
+{
+ struct resource *iores;
+
+ dev_dbg(dev, "probe\n");
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ muram.base = IOMEM(iores->start);
+ muram.size = resource_size(iores);
+ muram.alloc = muram.base + FM_MURAM_RES_SIZE;
+ muram.top = muram.base + muram.size;
+
+ return 0;
+}
+
+static struct of_device_id fsl_fman_mdio_dt_ids[] = {
+ {
+ .compatible = "fsl,fman-memac-mdio",
+ }, {
+ }
+};
+
+static struct driver_d fman_mdio_driver = {
+ .name = "fsl-fman-mdio",
+ .probe = fsl_fman_mdio_probe,
+ .of_compatible = DRV_OF_COMPAT(fsl_fman_mdio_dt_ids),
+};
+
+static struct of_device_id fsl_fman_port_dt_ids[] = {
+ {
+ .compatible = "fsl,fman-v3-port-rx",
+ .data = (void *)FMAN_PORT_TYPE_RX,
+ }, {
+ .compatible = "fsl,fman-v3-port-tx",
+ .data = (void *)FMAN_PORT_TYPE_TX,
+ }, {
+ }
+};
+
+static struct driver_d fman_port_driver = {
+ .name = "fsl-fman-port",
+ .probe = fsl_fman_port_probe,
+ .of_compatible = DRV_OF_COMPAT(fsl_fman_port_dt_ids),
+};
+
+static struct of_device_id fsl_fman_memac_dt_ids[] = {
+ {
+ .compatible = "fsl,fman-memac",
+ }, {
+ }
+};
+
+static struct driver_d fman_memac_driver = {
+ .name = "fsl-fman-memac",
+ .probe = fsl_fman_memac_probe,
+ .of_compatible = DRV_OF_COMPAT(fsl_fman_memac_dt_ids),
+};
+
+static struct of_device_id fsl_fman_muram_dt_ids[] = {
+ {
+ .compatible = "fsl,fman-muram",
+ }, {
+ }
+};
+
+static struct driver_d fman_muram_driver = {
+ .name = "fsl-fman-muram",
+ .probe = fsl_fman_muram_probe,
+ .of_compatible = DRV_OF_COMPAT(fsl_fman_muram_dt_ids),
+};
+
+static int fsl_fman_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ struct ccsr_fman *reg;
+ int ret;
+
+ dev_dbg(dev, "----------------> probe\n");
+
+ iores = dev_get_resource(dev, IORESOURCE_MEM, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ reg = IOMEM(iores->start);
+
+ ret = of_platform_populate(dev->device_node, NULL, dev);
+ if (ret)
+ return ret;
+
+ platform_driver_register(&fman_muram_driver);
+ platform_driver_register(&fman_mdio_driver);
+ platform_driver_register(&fman_port_driver);
+ platform_driver_register(&fman_memac_driver);
+
+ ret = fm_init_common(dev, reg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct of_device_id fsl_fman_dt_ids[] = {
+ {
+ .compatible = "fsl,fman",
+ }, {
+ }
+};
+
+static struct driver_d fman_driver = {
+ .name = "fsl-fman",
+ .probe = fsl_fman_probe,
+ .of_compatible = DRV_OF_COMPAT(fsl_fman_dt_ids),
+};
+device_platform_driver(fman_driver);