"Das U-Boot" Source Tree
at master 214 lines 5.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * LiteX Liteeth Ethernet 4 * 5 * Copyright 2021 Joel Stanley <joel@jms.id.au>, IBM Corp. 6 */ 7 8#include <linux/litex.h> 9 10#include <dm.h> 11#include <dm/device_compat.h> 12#include <net.h> 13 14#define LITEETH_WRITER_SLOT 0x00 15#define LITEETH_WRITER_LENGTH 0x04 16#define LITEETH_WRITER_ERRORS 0x08 17#define LITEETH_WRITER_EV_STATUS 0x0C 18#define LITEETH_WRITER_EV_PENDING 0x10 19#define LITEETH_WRITER_EV_ENABLE 0x14 20#define LITEETH_READER_START 0x18 21#define LITEETH_READER_READY 0x1C 22#define LITEETH_READER_LEVEL 0x20 23#define LITEETH_READER_SLOT 0x24 24#define LITEETH_READER_LENGTH 0x28 25#define LITEETH_READER_EV_STATUS 0x2C 26#define LITEETH_READER_EV_PENDING 0x30 27#define LITEETH_READER_EV_ENABLE 0x34 28#define LITEETH_PREAMBLE_CRC 0x38 29#define LITEETH_PREAMBLE_ERRORS 0x3C 30#define LITEETH_CRC_ERRORS 0x40 31 32struct liteeth { 33 struct udevice *dev; 34 35 void __iomem *base; 36 u32 slot_size; 37 38 /* Tx */ 39 u32 tx_slot; 40 u32 num_tx_slots; 41 void __iomem *tx_base; 42 43 /* Rx */ 44 u32 rx_slot; 45 u32 num_rx_slots; 46 void __iomem *rx_base; 47}; 48 49static int liteeth_recv(struct udevice *dev, int flags, uchar **packetp) 50{ 51 struct liteeth *priv = dev_get_priv(dev); 52 u8 rx_slot; 53 int len; 54 55 if (!litex_read8(priv->base + LITEETH_WRITER_EV_PENDING)) { 56 debug("liteeth: No packet ready\n"); 57 return -EAGAIN; 58 } 59 60 rx_slot = litex_read8(priv->base + LITEETH_WRITER_SLOT); 61 len = litex_read32(priv->base + LITEETH_WRITER_LENGTH); 62 63 debug("%s: slot %d len 0x%x\n", __func__, rx_slot, len); 64 65 *packetp = priv->rx_base + rx_slot * priv->slot_size; 66 67 return len; 68} 69 70static int liteeth_free_pkt(struct udevice *dev, uchar *packet, int length) 71{ 72 struct liteeth *priv = dev_get_priv(dev); 73 74 litex_write8(priv->base + LITEETH_WRITER_EV_PENDING, 1); 75 76 return 0; 77} 78 79static int liteeth_start(struct udevice *dev) 80{ 81 struct liteeth *priv = dev_get_priv(dev); 82 83 /* Clear pending events */ 84 litex_write8(priv->base + LITEETH_WRITER_EV_PENDING, 1); 85 litex_write8(priv->base + LITEETH_READER_EV_PENDING, 1); 86 87 /* Enable events */ 88 litex_write8(priv->base + LITEETH_WRITER_EV_ENABLE, 1); 89 litex_write8(priv->base + LITEETH_READER_EV_ENABLE, 1); 90 91 return 0; 92} 93 94static void liteeth_stop(struct udevice *dev) 95{ 96 struct liteeth *priv = dev_get_priv(dev); 97 98 litex_write8(priv->base + LITEETH_WRITER_EV_ENABLE, 0); 99 litex_write8(priv->base + LITEETH_READER_EV_ENABLE, 0); 100} 101 102static int liteeth_send(struct udevice *dev, void *packet, int len) 103{ 104 struct liteeth *priv = dev_get_priv(dev); 105 void __iomem *txbuffer; 106 107 if (!litex_read8(priv->base + LITEETH_READER_READY)) { 108 printf("liteeth: reader not ready\n"); 109 return -EAGAIN; 110 } 111 112 /* Reject oversize packets */ 113 if (unlikely(len > priv->slot_size)) 114 return -EMSGSIZE; 115 116 txbuffer = priv->tx_base + priv->tx_slot * priv->slot_size; 117 memcpy_toio(txbuffer, packet, len); 118 litex_write8(priv->base + LITEETH_READER_SLOT, priv->tx_slot); 119 litex_write16(priv->base + LITEETH_READER_LENGTH, len); 120 litex_write8(priv->base + LITEETH_READER_START, 1); 121 122 priv->tx_slot = (priv->tx_slot + 1) % priv->num_tx_slots; 123 124 return 0; 125} 126 127static void liteeth_setup_slots(struct liteeth *priv) 128{ 129 int err; 130 131 err = ofnode_read_u32(dev_ofnode(priv->dev), "litex,rx-slots", &priv->num_rx_slots); 132 if (err) { 133 dev_dbg(priv->dev, "unable to get litex,rx-slots, using 2\n"); 134 priv->num_rx_slots = 2; 135 } 136 137 err = ofnode_read_u32(dev_ofnode(priv->dev), "litex,tx-slots", &priv->num_tx_slots); 138 if (err) { 139 dev_dbg(priv->dev, "unable to get litex,tx-slots, using 2\n"); 140 priv->num_tx_slots = 2; 141 } 142 143 err = ofnode_read_u32(dev_ofnode(priv->dev), "litex,slot-size", &priv->slot_size); 144 if (err) { 145 dev_dbg(priv->dev, "unable to get litex,slot-size, using 0x800\n"); 146 priv->slot_size = 0x800; 147 } 148} 149 150static int liteeth_remove(struct udevice *dev) 151{ 152 liteeth_stop(dev); 153 154 return 0; 155} 156 157static const struct eth_ops liteeth_ops = { 158 .start = liteeth_start, 159 .stop = liteeth_stop, 160 .send = liteeth_send, 161 .recv = liteeth_recv, 162 .free_pkt = liteeth_free_pkt, 163}; 164 165static int liteeth_of_to_plat(struct udevice *dev) 166{ 167 struct eth_pdata *pdata = dev_get_plat(dev); 168 struct liteeth *priv = dev_get_priv(dev); 169 void __iomem *buf_base; 170 171 pdata->iobase = dev_read_addr(dev); 172 173 priv->dev = dev; 174 175 priv->base = dev_remap_addr_name(dev, "mac"); 176 if (!priv->base) { 177 dev_err(dev, "failed to map registers\n"); 178 return -EINVAL; 179 } 180 181 buf_base = dev_remap_addr_name(dev, "buffer"); 182 if (!buf_base) { 183 dev_err(dev, "failed to map buffer\n"); 184 return -EINVAL; 185 } 186 187 liteeth_setup_slots(priv); 188 189 /* Rx slots */ 190 priv->rx_base = buf_base; 191 priv->rx_slot = 0; 192 193 /* Tx slots come after Rx slots */ 194 priv->tx_base = buf_base + priv->num_rx_slots * priv->slot_size; 195 priv->tx_slot = 0; 196 197 return 0; 198} 199 200static const struct udevice_id liteeth_ids[] = { 201 { .compatible = "litex,liteeth" }, 202 {} 203}; 204 205U_BOOT_DRIVER(liteeth) = { 206 .name = "liteeth", 207 .id = UCLASS_ETH, 208 .of_match = liteeth_ids, 209 .of_to_plat = liteeth_of_to_plat, 210 .plat_auto = sizeof(struct eth_pdata), 211 .remove = liteeth_remove, 212 .ops = &liteeth_ops, 213 .priv_auto = sizeof(struct liteeth), 214};