mtd: spinand: toshiba: Support for new Kioxia Serial NAND
[oweals/u-boot.git] / drivers / net / ks8851_mll.c
index 1420ee9dbd9979e0339be8e9e8a9cd1fb11001d5..3ff173ad3391c7ff9a32873d0765761c8b59b356 100644 (file)
  * @extra_byte : number of extra byte prepended rx pkt.
  */
 struct ks_net {
+#ifndef CONFIG_DM_ETH
        struct eth_device       dev;
+#endif
        phys_addr_t             iobase;
        int                     bus_width;
        u16                     sharedbus;
+       u16                     rxfc;
        u8                      extra_byte;
 };
 
@@ -225,33 +228,31 @@ static inline void ks_read_qmu(struct ks_net *ks, u16 *buf, u32 len)
        ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL);
 }
 
-static void ks_rcv(struct ks_net *ks, uchar **pv_data)
+static int ks_rcv(struct ks_net *ks, uchar *data)
 {
-       unsigned int frame_cnt;
        u16 sts, len;
-       int i;
-
-       frame_cnt = ks_rdreg16(ks, KS_RXFCTR) >> 8;
-
-       /* read all header information */
-       for (i = 0; i < frame_cnt; i++) {
-               /* Checking Received packet status */
-               sts = ks_rdreg16(ks, KS_RXFHSR);
-               /* Get packet len from hardware */
-               len = ks_rdreg16(ks, KS_RXFHBCR);
-
-               if ((sts & RXFSHR_RXFV) && len && (len < RX_BUF_SIZE)) {
-                       /* read data block including CRC 4 bytes */
-                       ks_read_qmu(ks, (u16 *)(*pv_data), len);
-
-                       /* net_rx_packets buffer size is ok (*pv_data) */
-                       net_process_received_packet(*pv_data, len);
-                       pv_data++;
-               } else {
-                       ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_RRXEF);
-                       printf(DRIVERNAME ": bad packet\n");
-               }
+
+       if (!ks->rxfc)
+               ks->rxfc = ks_rdreg16(ks, KS_RXFCTR) >> 8;
+
+       if (!ks->rxfc)
+               return 0;
+
+       /* Checking Received packet status */
+       sts = ks_rdreg16(ks, KS_RXFHSR);
+       /* Get packet len from hardware */
+       len = ks_rdreg16(ks, KS_RXFHBCR);
+
+       if ((sts & RXFSHR_RXFV) && len && (len < RX_BUF_SIZE)) {
+               /* read data block including CRC 4 bytes */
+               ks_read_qmu(ks, (u16 *)data, len);
+               ks->rxfc--;
+               return len - 4;
        }
+
+       ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_RRXEF);
+       printf(DRIVERNAME ": bad packet\n");
+       return 0;
 }
 
 /*
@@ -395,10 +396,8 @@ static void ks8851_mll_enable(struct ks_net *ks)
        ks_enable_qmu(ks);
 }
 
-static int ks8851_mll_init(struct eth_device *dev, bd_t *bd)
+static int ks8851_mll_init_common(struct ks_net *ks)
 {
-       struct ks_net *ks = container_of(dev, struct ks_net, dev);
-
        if (ks_read_selftest(ks)) {
                printf(DRIVERNAME ": Selftest failed\n");
                return -1;
@@ -409,6 +408,8 @@ static int ks8851_mll_init(struct eth_device *dev, bd_t *bd)
        /* Configure the PHY, initialize the link state */
        ks8851_mll_phy_configure(ks);
 
+       ks->rxfc = 0;
+
        /* Turn on Tx + Rx */
        ks8851_mll_enable(ks);
 
@@ -437,9 +438,8 @@ static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len)
        do { } while (ks_rdreg16(ks, KS_TXQCR) & TXQCR_METFE);
 }
 
-static int ks8851_mll_send(struct eth_device *dev, void *packet, int length)
+static int ks8851_mll_send_common(struct ks_net *ks, void *packet, int length)
 {
-       struct ks_net *ks = container_of(dev, struct ks_net, dev);
        u8 *data = (u8 *)packet;
        u16 tmplen = (u16)length;
        u16 retv;
@@ -458,10 +458,8 @@ static int ks8851_mll_send(struct eth_device *dev, void *packet, int length)
        return -1;
 }
 
-static void ks8851_mll_halt(struct eth_device *dev)
+static void ks8851_mll_halt_common(struct ks_net *ks)
 {
-       struct ks_net *ks = container_of(dev, struct ks_net, dev);
-
        ks8851_mll_reset(ks);
 }
 
@@ -471,17 +469,17 @@ static void ks8851_mll_halt(struct eth_device *dev)
  * needs to be enough to prevent a packet being discarded while
  * we are processing the previous one.
  */
-static int ks8851_mll_recv(struct eth_device *dev)
+static int ks8851_mll_recv_common(struct ks_net *ks, uchar *data)
 {
-       struct ks_net *ks = container_of(dev, struct ks_net, dev);
        u16 status;
+       int ret = 0;
 
        status = ks_rdreg16(ks, KS_ISR);
 
        ks_wrreg16(ks, KS_ISR, status);
 
-       if (status & IRQ_RXI)
-               ks_rcv(ks, (uchar **)net_rx_packets);
+       if (ks->rxfc || (status & IRQ_RXI))
+               ret = ks_rcv(ks, data);
 
        if (status & IRQ_LDI) {
                u16 pmecr = ks_rdreg16(ks, KS_PMECR);
@@ -490,21 +488,61 @@ static int ks8851_mll_recv(struct eth_device *dev)
                ks_wrreg16(ks, KS_PMECR, pmecr | PMECR_WKEVT_LINK);
        }
 
-       return 0;
+       return ret;
 }
 
-static int ks8851_mll_write_hwaddr(struct eth_device *dev)
+static void ks8851_mll_write_hwaddr_common(struct ks_net *ks, u8 enetaddr[6])
 {
-       struct ks_net *ks = container_of(dev, struct ks_net, dev);
        u16 addrl, addrm, addrh;
 
-       addrh = (ks->dev.enetaddr[0] << 8) | ks->dev.enetaddr[1];
-       addrm = (ks->dev.enetaddr[2] << 8) | ks->dev.enetaddr[3];
-       addrl = (ks->dev.enetaddr[4] << 8) | ks->dev.enetaddr[5];
+       addrh = (enetaddr[0] << 8) | enetaddr[1];
+       addrm = (enetaddr[2] << 8) | enetaddr[3];
+       addrl = (enetaddr[4] << 8) | enetaddr[5];
 
        ks_wrreg16(ks, KS_MARH, addrh);
        ks_wrreg16(ks, KS_MARM, addrm);
        ks_wrreg16(ks, KS_MARL, addrl);
+}
+
+#ifndef CONFIG_DM_ETH
+static int ks8851_mll_init(struct eth_device *dev, bd_t *bd)
+{
+       struct ks_net *ks = container_of(dev, struct ks_net, dev);
+
+       return ks8851_mll_init_common(ks);
+}
+
+static void ks8851_mll_halt(struct eth_device *dev)
+{
+       struct ks_net *ks = container_of(dev, struct ks_net, dev);
+
+       ks8851_mll_halt_common(ks);
+}
+
+static int ks8851_mll_send(struct eth_device *dev, void *packet, int length)
+{
+       struct ks_net *ks = container_of(dev, struct ks_net, dev);
+
+       return ks8851_mll_send_common(ks, packet, length);
+}
+
+static int ks8851_mll_recv(struct eth_device *dev)
+{
+       struct ks_net *ks = container_of(dev, struct ks_net, dev);
+       int ret;
+
+       ret = ks8851_mll_recv_common(ks, net_rx_packets[0]);
+       if (ret)
+               net_process_received_packet(net_rx_packets[0], ret);
+
+       return ret;
+}
+
+static int ks8851_mll_write_hwaddr(struct eth_device *dev)
+{
+       struct ks_net *ks = container_of(dev, struct ks_net, dev);
+
+       ks8851_mll_write_hwaddr_common(ks, ks->dev.enetaddr);
 
        return 0;
 }
@@ -536,3 +574,103 @@ int ks8851_mll_initialize(u8 dev_num, int base_addr)
 
        return 0;
 }
+#else  /* ifdef CONFIG_DM_ETH */
+static int ks8851_start(struct udevice *dev)
+{
+       struct ks_net *ks = dev_get_priv(dev);
+
+       return ks8851_mll_init_common(ks);
+}
+
+static void ks8851_stop(struct udevice *dev)
+{
+       struct ks_net *ks = dev_get_priv(dev);
+
+       ks8851_mll_halt_common(ks);
+}
+
+static int ks8851_send(struct udevice *dev, void *packet, int length)
+{
+       struct ks_net *ks = dev_get_priv(dev);
+       int ret;
+
+       ret = ks8851_mll_send_common(ks, packet, length);
+
+       return ret ? 0 : -ETIMEDOUT;
+}
+
+static int ks8851_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+       struct ks_net *ks = dev_get_priv(dev);
+       uchar *data = net_rx_packets[0];
+       int ret;
+
+       ret = ks8851_mll_recv_common(ks, data);
+       if (ret)
+               *packetp = (void *)data;
+
+       return ret ? ret : -EAGAIN;
+}
+
+static int ks8851_write_hwaddr(struct udevice *dev)
+{
+       struct ks_net *ks = dev_get_priv(dev);
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+
+       ks8851_mll_write_hwaddr_common(ks, pdata->enetaddr);
+
+       return 0;
+}
+
+static int ks8851_bind(struct udevice *dev)
+{
+       return device_set_name(dev, dev->name);
+}
+
+static int ks8851_probe(struct udevice *dev)
+{
+       struct ks_net *ks = dev_get_priv(dev);
+
+       /* Try to detect chip. Will fail if not present. */
+       ks8851_mll_detect_chip(ks);
+
+       return 0;
+}
+
+static int ks8851_ofdata_to_platdata(struct udevice *dev)
+{
+       struct ks_net *ks = dev_get_priv(dev);
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+
+       pdata->iobase = devfdt_get_addr(dev);
+       ks->iobase = pdata->iobase;
+
+       return 0;
+}
+
+static const struct eth_ops ks8851_ops = {
+       .start          = ks8851_start,
+       .stop           = ks8851_stop,
+       .send           = ks8851_send,
+       .recv           = ks8851_recv,
+       .write_hwaddr   = ks8851_write_hwaddr,
+};
+
+static const struct udevice_id ks8851_ids[] = {
+       { .compatible = "micrel,ks8851-mll" },
+       { }
+};
+
+U_BOOT_DRIVER(ks8851) = {
+       .name           = "eth_ks8851",
+       .id             = UCLASS_ETH,
+       .of_match       = ks8851_ids,
+       .bind           = ks8851_bind,
+       .ofdata_to_platdata = ks8851_ofdata_to_platdata,
+       .probe          = ks8851_probe,
+       .ops            = &ks8851_ops,
+       .priv_auto_alloc_size = sizeof(struct ks_net),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+       .flags          = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif