@@ -212,6 +212,14 @@ typedef struct {
int rxp_offset;
int rxp_size;
int rxp_pad;
+
+ uint32_t write_word_prev_offset;
+ uint32_t write_word_n;
+ uint16_t write_word_l;
+ uint16_t write_word_h;
+ uint32_t read_word_prev_offset;
+ uint32_t read_word_n;
+ uint32_t read_long;
} lan9118_state;
static void lan9118_update(lan9118_state *s)
@@ -345,6 +353,9 @@ static void lan9118_reset(DeviceState *d)
s->mac_mii_data = 0;
s->mac_flow = 0;
+ s->read_word_n = 0;
+ s->write_word_n = 0;
+
phy_reset(s);
s->eeprom_writable = 0;
@@ -896,11 +907,11 @@ static void lan9118_tick(void *opaque)
}
static void lan9118_writel(void *opaque, target_phys_addr_t offset,
- uint64_t val, unsigned size)
+ uint32_t val)
{
lan9118_state *s = (lan9118_state *)opaque;
offset &= 0xff;
-
+
//DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
if (offset >= 0x20 && offset < 0x40) {
/* TX FIFO */
@@ -1029,8 +1040,43 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset,
lan9118_update(s);
}
-static uint64_t lan9118_readl(void *opaque, target_phys_addr_t offset,
- unsigned size)
+static void lan9118_writeb(void *opaque, target_phys_addr_t offset,
+ uint32_t val)
+{
+ hw_error("lan9118_writeb: Bad reg 0x%x = %x\n", (int)offset, val);
+}
+
+static void lan9118_writew(void *opaque, target_phys_addr_t offset,
+ uint32_t val)
+{
+ lan9118_state *s = (lan9118_state *)opaque;
+ offset &= 0xff;
+
+ /* TODO: Implement fair word operation, because this implementation
+ * assumes that any register is accessed as two 16-bit operations. */
+
+ if (s->write_word_prev_offset != (offset & ~0x3)) {
+ /* New offset, reset word counter */
+ s->write_word_n = 0;
+ s->write_word_prev_offset = offset & ~0x3;
+ }
+
+ if (offset & 0x2) {
+ s->write_word_h = val;
+ } else {
+ s->write_word_l = val;
+ }
+
+ //DPRINTF("Writew reg 0x%02x = 0x%08x\n", (int)offset, val);
+ s->write_word_n++;
+ if (s->write_word_n == 2) {
+ s->write_word_n = 0;
+ lan9118_writel(s, offset & ~3, s->write_word_l +
+ (s->write_word_h << 16));
+ }
+}
+
+static uint32_t lan9118_readl(void *opaque, target_phys_addr_t offset)
{
lan9118_state *s = (lan9118_state *)opaque;
@@ -1103,9 +1149,47 @@ static uint64_t lan9118_readl(void *opaque, target_phys_addr_t offset,
return 0;
}
+static uint32_t lan9118_readb(void *opaque, target_phys_addr_t offset)
+{
+ hw_error("lan9118_readb: Bad reg 0x%x\n", (int)offset);
+}
+
+static uint32_t lan9118_readw(void *opaque, target_phys_addr_t offset)
+{
+ lan9118_state *s = (lan9118_state *)opaque;
+ uint32_t val;
+
+ /* TODO: Implement fair word operation, because this implementation
+ * assumes that any register is accessed as two 16-bit operations. */
+
+ if (s->read_word_prev_offset != (offset & ~0x3)) {
+ /* New offset, reset word counter */
+ s->read_word_n = 0;
+ s->read_word_prev_offset = offset & ~0x3;
+ }
+
+ s->read_word_n++;
+ if (s->read_word_n == 1) {
+ s->read_long = lan9118_readl(s, offset & ~3);
+ } else {
+ s->read_word_n = 0;
+ }
+
+ if (offset & 2) {
+ val = s->read_long >> 16;
+ } else {
+ val = s->read_long & 0xFFFF;
+ }
+
+ //DPRINTF("Readw reg 0x%02x, val 0x%x\n", (int)offset, val);
+ return val;
+}
+
static const MemoryRegionOps lan9118_mem_ops = {
- .read = lan9118_readl,
- .write = lan9118_writel,
+ .old_mmio = {
+ .read = { lan9118_readb, lan9118_readw, lan9118_readl, },
+ .write = { lan9118_writeb, lan9118_writew, lan9118_writel, },
+ },
.endianness = DEVICE_NATIVE_ENDIAN,
};
We included this chip into s5pc210 platform because SMDK board holds lan9215 chip. Difference is that 9215 access is 16-bit wide and some registers differ. By addition basic 16-bit access to 9118 emulation we achieved ethernet controller support by Linux lernel on SMDK boards. Signed-off-by: Evgeny Voevodin <e.voevodin@samsung.com> --- hw/lan9118.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 90 insertions(+), 6 deletions(-)