qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 1/3] PPC4xx IIC and MAL


From: Salvatore Lionetti
Subject: [Qemu-devel] [PATCH 1/3] PPC4xx IIC and MAL
Date: Tue, 9 Dec 2008 01:46:55 +0000 (GMT)

Hi

This set of patch try to full support hw present in 'walnut' board.
http://elinux.org/DHT-Walnut

The fw used to successfully verify board is u-boot-1.3.4.

The only component not tested is PCI: perhaps should be a good start point for 
Hollis 's recent work, which i thanks for previous code review.

1) IIC: new eeprom device, full emulation of 4xx master core 
   MAL: Moved interface so can be shared with other modules
   4xx boards: move MAL & IIC common part between ppc4xx cpu
               add a list of created devices, so machine 2 phase creation is 
allowed,

   Warning: to compile:
   - comment line 'ppc4xx_emac_init(...)' in module hw/ppc405_boards.c
   - rename ppc405ep_init(args) in ppc405xp_init("405ep", args, NULL)

   Files changed:
   - Makefile.target
   - Makefile
   - hw/ppc405_uc.c
   - hw/ppc4xx_devs.c
   - hw/ppc405.h
   - hw/i2c.h
   - hw/iic_eeprom.c (Added)
   - hw/ppc4xx.h

Index: Makefile.target
===================================================================
--- Makefile.target     (revision 5720)
+++ Makefile.target     (working copy)
@@ -668,7 +668,7 @@
 ifeq ($(TARGET_BASE_ARCH), ppc)
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 # shared objects
-OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o
+OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o i2c.o openpic.o
 # PREP target
 OBJS+= pckbd.o ps2.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o
 OBJS+= prep_pci.o ppc_prep.o
@@ -679,7 +679,7 @@
 # NewWorld PowerMac
 OBJS+= unin_pci.o ppc_chrp.o
 # PowerPC 4xx boards
-OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o
+OBJS+= pflash_cfi02.o ppc4xx_emac.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o
 endif
 ifeq ($(TARGET_BASE_ARCH), mips)
 OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
Index: Makefile
===================================================================
--- Makefile    (revision 5720)
+++ Makefile    (working copy)
@@ -69,7 +69,7 @@
 OBJS+=readline.o console.o
 
 OBJS+=irq.o
-OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
+OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o iic_eeprom.o
 OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
 OBJS+=tmp105.o lm832x.o
 OBJS+=scsi-disk.o cdrom.o
Index: hw/ppc405_uc.c
===================================================================
--- hw/ppc405_uc.c      (revision 5720)
+++ hw/ppc405_uc.c      (working copy)
@@ -21,6 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <assert.h>
 #include "hw.h"
 #include "ppc.h"
 #include "ppc405.h"
@@ -28,13 +29,17 @@
 #include "qemu-timer.h"
 #include "sysemu.h"
 #include "qemu-log.h"
+#include "net.h" /* To have nd_table.h */
 
+extern int loglevel;
+extern FILE *logfile;
+
 #define DEBUG_OPBA
 #define DEBUG_SDRAM
-#define DEBUG_GPIO
+/*#define DEBUG_GPIO*/
 #define DEBUG_SERIAL
 #define DEBUG_OCM
-//#define DEBUG_I2C
+/*#define DEBUG_I2C*/
 #define DEBUG_GPT
 #define DEBUG_MAL
 #define DEBUG_CLOCKS
@@ -835,6 +840,8 @@
             ret = 0x00000000;
             break;
         }
+       printf("Read ebc[%d]=>%x\n", ebc->addr, ret);
+       break;
     default:
         ret = 0x00000000;
         break;
@@ -853,6 +860,7 @@
         ebc->addr = val;
         break;
     case EBC0_CFGDATA:
+       printf("Write ebc[%d]=>%x\n", ebc->addr, val);
         switch (ebc->addr) {
         case 0x00: /* B0CR */
             break;
@@ -1395,252 +1403,6 @@
 }
 
 /*****************************************************************************/
-/* I2C controller */
-typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
-struct ppc4xx_i2c_t {
-    target_phys_addr_t base;
-    qemu_irq irq;
-    uint8_t mdata;
-    uint8_t lmadr;
-    uint8_t hmadr;
-    uint8_t cntl;
-    uint8_t mdcntl;
-    uint8_t sts;
-    uint8_t extsts;
-    uint8_t sdata;
-    uint8_t lsadr;
-    uint8_t hsadr;
-    uint8_t clkdiv;
-    uint8_t intrmsk;
-    uint8_t xfrcnt;
-    uint8_t xtcntlss;
-    uint8_t directcntl;
-};
-
-static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr)
-{
-    ppc4xx_i2c_t *i2c;
-    uint32_t ret;
-
-#ifdef DEBUG_I2C
-    printf("%s: addr " PADDRX "\n", __func__, addr);
-#endif
-    i2c = opaque;
-    switch (addr - i2c->base) {
-    case 0x00:
-        //        i2c_readbyte(&i2c->mdata);
-        ret = i2c->mdata;
-        break;
-    case 0x02:
-        ret = i2c->sdata;
-        break;
-    case 0x04:
-        ret = i2c->lmadr;
-        break;
-    case 0x05:
-        ret = i2c->hmadr;
-        break;
-    case 0x06:
-        ret = i2c->cntl;
-        break;
-    case 0x07:
-        ret = i2c->mdcntl;
-        break;
-    case 0x08:
-        ret = i2c->sts;
-        break;
-    case 0x09:
-        ret = i2c->extsts;
-        break;
-    case 0x0A:
-        ret = i2c->lsadr;
-        break;
-    case 0x0B:
-        ret = i2c->hsadr;
-        break;
-    case 0x0C:
-        ret = i2c->clkdiv;
-        break;
-    case 0x0D:
-        ret = i2c->intrmsk;
-        break;
-    case 0x0E:
-        ret = i2c->xfrcnt;
-        break;
-    case 0x0F:
-        ret = i2c->xtcntlss;
-        break;
-    case 0x10:
-        ret = i2c->directcntl;
-        break;
-    default:
-        ret = 0x00;
-        break;
-    }
-#ifdef DEBUG_I2C
-    printf("%s: addr " PADDRX " %02" PRIx32 "\n", __func__, addr, ret);
-#endif
-
-    return ret;
-}
-
-static void ppc4xx_i2c_writeb (void *opaque,
-                               target_phys_addr_t addr, uint32_t value)
-{
-    ppc4xx_i2c_t *i2c;
-
-#ifdef DEBUG_I2C
-    printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value);
-#endif
-    i2c = opaque;
-    switch (addr - i2c->base) {
-    case 0x00:
-        i2c->mdata = value;
-        //        i2c_sendbyte(&i2c->mdata);
-        break;
-    case 0x02:
-        i2c->sdata = value;
-        break;
-    case 0x04:
-        i2c->lmadr = value;
-        break;
-    case 0x05:
-        i2c->hmadr = value;
-        break;
-    case 0x06:
-        i2c->cntl = value;
-        break;
-    case 0x07:
-        i2c->mdcntl = value & 0xDF;
-        break;
-    case 0x08:
-        i2c->sts &= ~(value & 0x0A);
-        break;
-    case 0x09:
-        i2c->extsts &= ~(value & 0x8F);
-        break;
-    case 0x0A:
-        i2c->lsadr = value;
-        break;
-    case 0x0B:
-        i2c->hsadr = value;
-        break;
-    case 0x0C:
-        i2c->clkdiv = value;
-        break;
-    case 0x0D:
-        i2c->intrmsk = value;
-        break;
-    case 0x0E:
-        i2c->xfrcnt = value & 0x77;
-        break;
-    case 0x0F:
-        i2c->xtcntlss = value;
-        break;
-    case 0x10:
-        i2c->directcntl = value & 0x7;
-        break;
-    }
-}
-
-static uint32_t ppc4xx_i2c_readw (void *opaque, target_phys_addr_t addr)
-{
-    uint32_t ret;
-
-#ifdef DEBUG_I2C
-    printf("%s: addr " PADDRX "\n", __func__, addr);
-#endif
-    ret = ppc4xx_i2c_readb(opaque, addr) << 8;
-    ret |= ppc4xx_i2c_readb(opaque, addr + 1);
-
-    return ret;
-}
-
-static void ppc4xx_i2c_writew (void *opaque,
-                               target_phys_addr_t addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
-    printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value);
-#endif
-    ppc4xx_i2c_writeb(opaque, addr, value >> 8);
-    ppc4xx_i2c_writeb(opaque, addr + 1, value);
-}
-
-static uint32_t ppc4xx_i2c_readl (void *opaque, target_phys_addr_t addr)
-{
-    uint32_t ret;
-
-#ifdef DEBUG_I2C
-    printf("%s: addr " PADDRX "\n", __func__, addr);
-#endif
-    ret = ppc4xx_i2c_readb(opaque, addr) << 24;
-    ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16;
-    ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8;
-    ret |= ppc4xx_i2c_readb(opaque, addr + 3);
-
-    return ret;
-}
-
-static void ppc4xx_i2c_writel (void *opaque,
-                               target_phys_addr_t addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
-    printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value);
-#endif
-    ppc4xx_i2c_writeb(opaque, addr, value >> 24);
-    ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16);
-    ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8);
-    ppc4xx_i2c_writeb(opaque, addr + 3, value);
-}
-
-static CPUReadMemoryFunc *i2c_read[] = {
-    &ppc4xx_i2c_readb,
-    &ppc4xx_i2c_readw,
-    &ppc4xx_i2c_readl,
-};
-
-static CPUWriteMemoryFunc *i2c_write[] = {
-    &ppc4xx_i2c_writeb,
-    &ppc4xx_i2c_writew,
-    &ppc4xx_i2c_writel,
-};
-
-static void ppc4xx_i2c_reset (void *opaque)
-{
-    ppc4xx_i2c_t *i2c;
-
-    i2c = opaque;
-    i2c->mdata = 0x00;
-    i2c->sdata = 0x00;
-    i2c->cntl = 0x00;
-    i2c->mdcntl = 0x00;
-    i2c->sts = 0x00;
-    i2c->extsts = 0x00;
-    i2c->clkdiv = 0x00;
-    i2c->xfrcnt = 0x00;
-    i2c->directcntl = 0x0F;
-}
-
-void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio,
-                      target_phys_addr_t offset, qemu_irq irq)
-{
-    ppc4xx_i2c_t *i2c;
-
-    i2c = qemu_mallocz(sizeof(ppc4xx_i2c_t));
-    if (i2c != NULL) {
-        i2c->base = offset;
-        i2c->irq = irq;
-        ppc4xx_i2c_reset(i2c);
-#ifdef DEBUG_I2C
-        printf("%s: offset " PADDRX "\n", __func__, offset);
-#endif
-        ppc4xx_mmio_register(env, mmio, offset, 0x011,
-                             i2c_read, i2c_write, i2c);
-        qemu_register_reset(ppc4xx_i2c_reset, i2c);
-    }
-}
-
-/*****************************************************************************/
 /* General purpose timers */
 typedef struct ppc4xx_gpt_t ppc4xx_gpt_t;
 struct ppc4xx_gpt_t {
@@ -1925,271 +1687,6 @@
 }
 
 /*****************************************************************************/
-/* MAL */
-enum {
-    MAL0_CFG      = 0x180,
-    MAL0_ESR      = 0x181,
-    MAL0_IER      = 0x182,
-    MAL0_TXCASR   = 0x184,
-    MAL0_TXCARR   = 0x185,
-    MAL0_TXEOBISR = 0x186,
-    MAL0_TXDEIR   = 0x187,
-    MAL0_RXCASR   = 0x190,
-    MAL0_RXCARR   = 0x191,
-    MAL0_RXEOBISR = 0x192,
-    MAL0_RXDEIR   = 0x193,
-    MAL0_TXCTP0R  = 0x1A0,
-    MAL0_TXCTP1R  = 0x1A1,
-    MAL0_TXCTP2R  = 0x1A2,
-    MAL0_TXCTP3R  = 0x1A3,
-    MAL0_RXCTP0R  = 0x1C0,
-    MAL0_RXCTP1R  = 0x1C1,
-    MAL0_RCBS0    = 0x1E0,
-    MAL0_RCBS1    = 0x1E1,
-};
-
-typedef struct ppc40x_mal_t ppc40x_mal_t;
-struct ppc40x_mal_t {
-    qemu_irq irqs[4];
-    uint32_t cfg;
-    uint32_t esr;
-    uint32_t ier;
-    uint32_t txcasr;
-    uint32_t txcarr;
-    uint32_t txeobisr;
-    uint32_t txdeir;
-    uint32_t rxcasr;
-    uint32_t rxcarr;
-    uint32_t rxeobisr;
-    uint32_t rxdeir;
-    uint32_t txctpr[4];
-    uint32_t rxctpr[2];
-    uint32_t rcbs[2];
-};
-
-static void ppc40x_mal_reset (void *opaque);
-
-static target_ulong dcr_read_mal (void *opaque, int dcrn)
-{
-    ppc40x_mal_t *mal;
-    target_ulong ret;
-
-    mal = opaque;
-    switch (dcrn) {
-    case MAL0_CFG:
-        ret = mal->cfg;
-        break;
-    case MAL0_ESR:
-        ret = mal->esr;
-        break;
-    case MAL0_IER:
-        ret = mal->ier;
-        break;
-    case MAL0_TXCASR:
-        ret = mal->txcasr;
-        break;
-    case MAL0_TXCARR:
-        ret = mal->txcarr;
-        break;
-    case MAL0_TXEOBISR:
-        ret = mal->txeobisr;
-        break;
-    case MAL0_TXDEIR:
-        ret = mal->txdeir;
-        break;
-    case MAL0_RXCASR:
-        ret = mal->rxcasr;
-        break;
-    case MAL0_RXCARR:
-        ret = mal->rxcarr;
-        break;
-    case MAL0_RXEOBISR:
-        ret = mal->rxeobisr;
-        break;
-    case MAL0_RXDEIR:
-        ret = mal->rxdeir;
-        break;
-    case MAL0_TXCTP0R:
-        ret = mal->txctpr[0];
-        break;
-    case MAL0_TXCTP1R:
-        ret = mal->txctpr[1];
-        break;
-    case MAL0_TXCTP2R:
-        ret = mal->txctpr[2];
-        break;
-    case MAL0_TXCTP3R:
-        ret = mal->txctpr[3];
-        break;
-    case MAL0_RXCTP0R:
-        ret = mal->rxctpr[0];
-        break;
-    case MAL0_RXCTP1R:
-        ret = mal->rxctpr[1];
-        break;
-    case MAL0_RCBS0:
-        ret = mal->rcbs[0];
-        break;
-    case MAL0_RCBS1:
-        ret = mal->rcbs[1];
-        break;
-    default:
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_mal (void *opaque, int dcrn, target_ulong val)
-{
-    ppc40x_mal_t *mal;
-    int idx;
-
-    mal = opaque;
-    switch (dcrn) {
-    case MAL0_CFG:
-        if (val & 0x80000000)
-            ppc40x_mal_reset(mal);
-        mal->cfg = val & 0x00FFC087;
-        break;
-    case MAL0_ESR:
-        /* Read/clear */
-        mal->esr &= ~val;
-        break;
-    case MAL0_IER:
-        mal->ier = val & 0x0000001F;
-        break;
-    case MAL0_TXCASR:
-        mal->txcasr = val & 0xF0000000;
-        break;
-    case MAL0_TXCARR:
-        mal->txcarr = val & 0xF0000000;
-        break;
-    case MAL0_TXEOBISR:
-        /* Read/clear */
-        mal->txeobisr &= ~val;
-        break;
-    case MAL0_TXDEIR:
-        /* Read/clear */
-        mal->txdeir &= ~val;
-        break;
-    case MAL0_RXCASR:
-        mal->rxcasr = val & 0xC0000000;
-        break;
-    case MAL0_RXCARR:
-        mal->rxcarr = val & 0xC0000000;
-        break;
-    case MAL0_RXEOBISR:
-        /* Read/clear */
-        mal->rxeobisr &= ~val;
-        break;
-    case MAL0_RXDEIR:
-        /* Read/clear */
-        mal->rxdeir &= ~val;
-        break;
-    case MAL0_TXCTP0R:
-        idx = 0;
-        goto update_tx_ptr;
-    case MAL0_TXCTP1R:
-        idx = 1;
-        goto update_tx_ptr;
-    case MAL0_TXCTP2R:
-        idx = 2;
-        goto update_tx_ptr;
-    case MAL0_TXCTP3R:
-        idx = 3;
-    update_tx_ptr:
-        mal->txctpr[idx] = val;
-        break;
-    case MAL0_RXCTP0R:
-        idx = 0;
-        goto update_rx_ptr;
-    case MAL0_RXCTP1R:
-        idx = 1;
-    update_rx_ptr:
-        mal->rxctpr[idx] = val;
-        break;
-    case MAL0_RCBS0:
-        idx = 0;
-        goto update_rx_size;
-    case MAL0_RCBS1:
-        idx = 1;
-    update_rx_size:
-        mal->rcbs[idx] = val & 0x000000FF;
-        break;
-    }
-}
-
-static void ppc40x_mal_reset (void *opaque)
-{
-    ppc40x_mal_t *mal;
-
-    mal = opaque;
-    mal->cfg = 0x0007C000;
-    mal->esr = 0x00000000;
-    mal->ier = 0x00000000;
-    mal->rxcasr = 0x00000000;
-    mal->rxdeir = 0x00000000;
-    mal->rxeobisr = 0x00000000;
-    mal->txcasr = 0x00000000;
-    mal->txdeir = 0x00000000;
-    mal->txeobisr = 0x00000000;
-}
-
-void ppc405_mal_init (CPUState *env, qemu_irq irqs[4])
-{
-    ppc40x_mal_t *mal;
-    int i;
-
-    mal = qemu_mallocz(sizeof(ppc40x_mal_t));
-    if (mal != NULL) {
-        for (i = 0; i < 4; i++)
-            mal->irqs[i] = irqs[i];
-        ppc40x_mal_reset(mal);
-        qemu_register_reset(&ppc40x_mal_reset, mal);
-        ppc_dcr_register(env, MAL0_CFG,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_ESR,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_IER,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_TXCASR,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_TXCARR,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_TXEOBISR,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_TXDEIR,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_RXCASR,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_RXCARR,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_RXEOBISR,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_RXDEIR,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_TXCTP0R,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_TXCTP1R,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_TXCTP2R,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_TXCTP3R,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_RXCTP0R,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_RXCTP1R,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_RCBS0,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-        ppc_dcr_register(env, MAL0_RCBS1,
-                         mal, &dcr_read_mal, &dcr_write_mal);
-    }
-}
-
-/*****************************************************************************/
 /* SPR */
 void ppc40x_core_reset (CPUState *env)
 {
@@ -2234,6 +1731,7 @@
     qemu_system_reset_request();
 }
 
+/* ->halted=1 seem that loose memory. */
 void store_40x_dbcr0 (CPUState *env, uint32_t val)
 {
     switch ((val >> 28) & 0x3) {
@@ -2541,12 +2039,14 @@
 CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
                          target_phys_addr_t ram_sizes[4],
                          uint32_t sysclk, qemu_irq **picp,
-                         ram_addr_t *offsetp, int do_init)
+                         ram_addr_t *offsetp, int do_init,
+                         ppc4xx_devsL *devsL)
 {
     clk_setup_t clk_setup[PPC405CR_CLK_NB];
     qemu_irq dma_irqs[4];
     CPUState *env;
     ppc4xx_mmio_t *mmio;
+    ppc4xx_i2c_t *i2c;
     qemu_irq *pic, *irqs;
     ram_addr_t offset;
     int i;
@@ -2591,13 +2091,16 @@
         ppc405_serial_init(env, mmio, 0x400, pic[1], serial_hds[1]);
     }
     /* IIC controller */
-    ppc405_i2c_init(env, mmio, 0x500, pic[2]);
+    i2c = ppc4xx_i2c_init(env, mmio, 0x500, pic[2]);
     /* GPIO */
     ppc405_gpio_init(env, mmio, 0x700);
     /* CPU control */
     ppc405cr_cpc_init(env, clk_setup, sysclk);
     *offsetp = offset;
 
+    if (devsL) {
+           devsL->i2c0 = i2c;
+    }
     return env;
 }
 
@@ -2891,22 +2394,28 @@
     }
 }
 
-CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
+CPUState *ppc405xp_init (const char* cpu_model,
+                         target_phys_addr_t ram_bases[2],
                          target_phys_addr_t ram_sizes[2],
                          uint32_t sysclk, qemu_irq **picp,
-                         ram_addr_t *offsetp, int do_init)
+                         ram_addr_t *offsetp, int do_init,
+                         struct ppc4xx_devsL *devsL)
 {
     clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
-    qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
+    qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[5];
     CPUState *env;
     ppc4xx_mmio_t *mmio;
     qemu_irq *pic, *irqs;
     ram_addr_t offset;
+    ppc4xx_mal_t *mal;
+    ppc4xx_i2c_t *i2c;
     int i;
 
     memset(clk_setup, 0, sizeof(clk_setup));
     /* init CPUs */
-    env = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK],
+    if (!cpu_model)
+           cpu_model = "405ep";
+    env = ppc4xx_init(cpu_model, &clk_setup[PPC405EP_CPU_CLK],
                       &tlb_clk_setup, sysclk);
     clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb;
     clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque;
@@ -2942,7 +2451,7 @@
     dma_irqs[3] = pic[8];
     ppc405_dma_init(env, dma_irqs);
     /* IIC controller */
-    ppc405_i2c_init(env, mmio, 0x500, pic[2]);
+    i2c = ppc4xx_i2c_init(env, mmio, 0x500, pic[2]);
     /* GPIO */
     ppc405_gpio_init(env, mmio, 0x700);
     /* Serial ports */
@@ -2965,16 +2474,21 @@
     /* PCI */
     /* Uses pic[3], pic[16], pic[18] */
     /* MAL */
-    mal_irqs[0] = pic[11];
-    mal_irqs[1] = pic[12];
-    mal_irqs[2] = pic[13];
-    mal_irqs[3] = pic[14];
-    ppc405_mal_init(env, mal_irqs);
-    /* Ethernet */
+    mal_irqs[0] = pic[11]; /* TX end of buffer */
+    mal_irqs[1] = pic[12]; /* RX end of buffer */
+    mal_irqs[2] = pic[13]; /* TX data error    */
+    mal_irqs[3] = pic[14]; /* RX data error    */
+    mal_irqs[4] = pic[10]; /* Mal System error */
+    mal = ppc4xx_mal_init(env, mal_irqs);
+    /* EMAC (Ethernet Media Access Controller) */
+    ppc4xx_emac_init(env, mmio, 0x800, &nd_table[0], mal);
     /* Uses pic[9], pic[15], pic[17] */
     /* CPU control */
     ppc405ep_cpc_init(env, clk_setup, sysclk);
     *offsetp = offset;
 
+    if (devsL) {
+           devsL->i2c0 = i2c;
+    }
     return env;
 }
Index: hw/ppc4xx_devs.c
===================================================================
--- hw/ppc4xx_devs.c    (revision 5720)
+++ hw/ppc4xx_devs.c    (working copy)
@@ -21,15 +21,19 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <assert.h>
 #include "hw.h"
 #include "ppc.h"
 #include "ppc4xx.h"
 #include "sysemu.h"
 #include "qemu-log.h"
+#include "qemu-timer.h"
 
 //#define DEBUG_MMIO
 //#define DEBUG_UNASSIGNED
 #define DEBUG_UIC
+//#define DEBUG_I2C
+#define I2C_USE_EXISTING 1
 
 /*****************************************************************************/
 /* Generic PowerPC 4xx processor instanciation */
@@ -296,10 +300,10 @@
     cr = uic->uicsr & uic->uicer & uic->uiccr;
 #ifdef DEBUG_UIC
     if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "%s: uicsr %08" PRIx32 " uicer %08" PRIx32
+        fprintf(logfile, "%s %" PRIu64 ": uicsr %08" PRIx32 " uicer %08" PRIx32
                 " uiccr %08" PRIx32 "\n"
                 "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
-                __func__, uic->uicsr, uic->uicer, uic->uiccr,
+                __func__, qemu_get_clock(rt_clock), uic->uicsr, uic->uicer, 
uic->uiccr,
                 uic->uicsr & uic->uicer, ir, cr);
     }
 #endif
@@ -366,9 +370,9 @@
     mask = 1 << (31-irq_num);
 #ifdef DEBUG_UIC
     if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "%s: irq %d level %d uicsr %08" PRIx32
+        fprintf(logfile, "%s %" PRIu64 ": irq %d level %d uicsr %08" PRIx32
                 " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
-                __func__, irq_num, level,
+                __func__, qemu_get_clock(rt_clock), irq_num, level,
                 uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
     }
 #endif
@@ -532,3 +536,756 @@
 
     return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
 }
+
+
+/*****************************************************************************/
+/* MAL */
+/* TODO: INTEGRATION IN PROGRESS
+ * Tested successfully on
+ * - 405GPr(OSE/Proprietary NSN 4G Board),
+ * - 405EP (u-boot-1.1.6/DHT Walnut),
+ *
+ * Modified (need test) for
+ * - 440ep.
+ *
+ * There is a number of variant among PowerPC4xx uP.
+ * However basic work can be reused.
+ *
+ * VARIANT KNOWN:
+ *
+ * 440ep
+ *     serial device register: SDR0_MAL{R,T}x{BL,BS}
+ *                  DCR        @reset
+ *     SDR0_MALRBL, 2A0        0x55550000 #word to transfer in a single 
transact.
+ *     SDR0_MALRBS, 2E0        0xF0000000
+ *     SDR0_MALTBL, 280        0x55550000 #Reserver
+ *     SDR0_MALTBS, 2C0        0xF0000000
+ *      4 TX channel, 2 RX channel
+ *     MAL0_RXCTP1R (already present)
+ *     MAL0_RCBS1   (already present)
+ *
+ *
+ * 
+ * number of tx channel {1, 2}
+ * 440 has txbattr register
+ * 440SPE, 440EPX, 440GRX have different content of IER. ESR
+ * Interrupt enable register: all such cause muxed on SERR
+Common
+#define MAL_IER_DE       0x00000010 * Descriptor erro
+#define MAL_IER_TE       0x00000004 * OPB Time Out error
+#define MAL_IER_OPBE     0x00000002 * OPB Slave error
+#define MAL_IER_PLBE     0x00000001 * PLB Bus error
+
+440SPE, 440EPX, 440GRX
+#define MAL_IER_PT       0x00000080
+#define MAL_IER_PRE      0x00000040
+#define MAL_IER_PWE      0x00000020
+
+Other
+#define MAL_IER_NE       0x00000008 * OPB Non word error
+ *
+ * 
+ * 
+ * TODO:
+ * NO ERRATA IS IMPLEMENTED HERE!
+ * Es PPC440GP_RB: Errata 1.12: MAL_1 -- Disable MAL bursting 
+ */
+
+enum {
+    MAL0_CFG      = 0x180,
+    MAL0_ESR      = 0x181,
+    MAL0_IER      = 0x182,
+    MAL0_TXCASR   = 0x184,
+    MAL0_TXCARR   = 0x185,
+    MAL0_TXEOBISR = 0x186,
+    MAL0_TXDEIR   = 0x187,
+    MAL0_RXCASR   = 0x190,
+    MAL0_RXCARR   = 0x191,
+    MAL0_RXEOBISR = 0x192,
+    MAL0_RXDEIR   = 0x193,
+    MAL0_TXCTP0R  = 0x1A0,
+    MAL0_TXCTP1R  = 0x1A1,
+    MAL0_TXCTP2R  = 0x1A2,
+    MAL0_TXCTP3R  = 0x1A3,
+    MAL0_RXCTP0R  = 0x1C0,
+    MAL0_RXCTP1R  = 0x1C1,
+    MAL0_RCBS0    = 0x1E0,
+    MAL0_RCBS1    = 0x1E1,
+    /* For ppc440ep System device control */
+    SDR0_MALTBL   = 0x280,
+    SDR0_MALRBL   = 0x2A0,
+    SDR0_MALTBS   = 0x2C0,
+    SDR0_MALRBS   = 0x2E0,
+};
+
+static void ppc4xx_mal_reset (void *opaque);
+
+static target_ulong dcr_read_mal (void *opaque, int dcrn)
+{
+    ppc4xx_mal_t *mal;
+    target_ulong ret;
+
+    mal = opaque;
+    switch (dcrn) {
+    case MAL0_CFG:
+        ret = mal->cfg;
+        break;
+    case MAL0_ESR:
+        ret = mal->esr;
+        break;
+    case MAL0_IER:
+        ret = mal->ier;
+        break;
+    case MAL0_TXCASR:
+        ret = mal->txcasr;
+        break;
+    case MAL0_TXCARR:
+        ret = mal->txcarr;
+        break;
+    case MAL0_TXEOBISR:
+        ret = mal->txeobisr;
+        break;
+    case MAL0_TXDEIR:
+        ret = mal->txdeir;
+        break;
+    case MAL0_RXCASR:
+        ret = mal->rxcasr;
+        break;
+    case MAL0_RXCARR:
+        ret = mal->rxcarr;
+        break;
+    case MAL0_RXEOBISR:
+        ret = mal->rxeobisr;
+        break;
+    case MAL0_RXDEIR:
+        ret = mal->rxdeir;
+        break;
+    case MAL0_TXCTP0R:
+        ret = mal->txctpr[0];
+        break;
+    case MAL0_TXCTP1R:
+        ret = mal->txctpr[1];
+        break;
+    case MAL0_TXCTP2R:
+        ret = mal->txctpr[2];
+        break;
+    case MAL0_TXCTP3R:
+        ret = mal->txctpr[3];
+        break;
+    case MAL0_RXCTP0R:
+        ret = mal->rxctpr[0];
+        break;
+    case MAL0_RXCTP1R:
+        ret = mal->rxctpr[1];
+        break;
+    case MAL0_RCBS0:
+        ret = mal->rcbs[0];
+        break;
+    case MAL0_RCBS1:
+        ret = mal->rcbs[1];
+        break;
+    case SDR0_MALTBL:
+       ret = mal->tbl;
+       break;
+    case SDR0_MALRBL:
+       ret = mal->rbl;
+       break;
+    case SDR0_MALTBS:
+       ret = mal->tbs;
+       break;
+    case SDR0_MALRBS:
+       ret = mal->rbs;
+       break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_mal (void *opaque, int dcrn, target_ulong val)
+{
+    ppc4xx_mal_t *mal;
+    int idx;
+
+    mal = opaque;
+    switch (dcrn) {
+    case MAL0_CFG:
+        if (val & 0x80000000)
+            ppc4xx_mal_reset(mal);
+        mal->cfg = val & 0x00FFC087;
+        break;
+    case MAL0_ESR:
+        /* Read/clear */
+        mal->esr &= ~val;
+        break;
+    case MAL0_IER:
+        mal->ier = val & 0x0000001F;
+        break;
+    case MAL0_TXCASR:
+        mal->txcasr = val & 0xF0000000;
+        break;
+    case MAL0_TXCARR:
+        mal->txcarr = val & 0xF0000000;
+        break;
+    case MAL0_TXEOBISR:
+        /* Read/clear TODO SEPARATE CHANNEL */
+       if (mal->txeobisr & val & 0xC0000000) {
+               mal->txeobisr &= ~val;
+               qemu_irq_lower(mal->txeob);
+       }
+       mal->txeobisr &= ~val;
+        break;
+    case MAL0_TXDEIR:
+        /* Read/clear */
+        mal->txdeir &= ~val;
+        break;
+    case MAL0_RXCASR:
+        mal->rxcasr = val & ~0xC0000000; /* Active Set immediately rx channel 
*/
+        break;
+    case MAL0_RXCARR:
+        mal->rxcarr = val & 0xC0000000;
+        break;
+    case MAL0_RXEOBISR:
+        /* Read/clear */
+       if (mal->rxeobisr & val & 0x80000000) {
+               mal->rxeobisr &= ~val;
+               qemu_irq_lower(mal->rxeob);
+       }
+        mal->rxeobisr &= ~val;
+        break;
+    case MAL0_RXDEIR:
+        /* Read/clear */
+        mal->rxdeir &= ~val;
+        break;
+    case MAL0_TXCTP0R:
+        idx = 0;
+        goto update_tx_ptr;
+    case MAL0_TXCTP1R:
+        idx = 1;
+        goto update_tx_ptr;
+    case MAL0_TXCTP2R:
+        idx = 2;
+        goto update_tx_ptr;
+    case MAL0_TXCTP3R:
+        idx = 3;
+    update_tx_ptr:
+        mal->txctpr[idx] = val;
+        break;
+    case MAL0_RXCTP0R:
+        idx = 0;
+        goto update_rx_ptr;
+    case MAL0_RXCTP1R:
+        idx = 1;
+    update_rx_ptr:
+        mal->rxctpr[idx] = val;
+        break;
+    case MAL0_RCBS0:
+        idx = 0;
+        goto update_rx_size;
+    case MAL0_RCBS1:
+        idx = 1;
+    update_rx_size:
+        mal->rcbs[idx] = val & 0x000000FF;
+        break;
+    case SDR0_MALTBL:
+       mal->tbl = val;
+       break;
+    case SDR0_MALRBL:
+       mal->rbl = val;
+       break;
+    case SDR0_MALTBS:
+       mal->tbs = val;
+       break;
+    case SDR0_MALRBS:
+       mal->rbs = val;
+       break;
+    }
+}
+
+static void ppc4xx_mal_reset (void *opaque)
+{
+    ppc4xx_mal_t *mal;
+
+    mal = opaque;
+    mal->cfg = 0x0007C000;
+    mal->esr = 0x00000000;
+    mal->ier = 0x00000000;
+    mal->rxcasr = 0x00000000;
+    mal->rxdeir = 0x00000000;
+    mal->rxeobisr = 0x00000000;
+    mal->txcasr = 0x00000000;
+    mal->txdeir = 0x00000000;
+    mal->txeobisr = 0x00000000;
+}
+
+ppc4xx_mal_t *ppc4xx_mal_init (CPUState *env, qemu_irq irqs[4])
+{
+    ppc4xx_mal_t *mal;
+
+    mal = qemu_mallocz(sizeof(ppc4xx_mal_t));
+    if (mal != NULL) {
+        mal->txeob = irqs[0];
+        mal->rxeob = irqs[1];
+        mal->txde  = irqs[2];
+        mal->rxde  = irqs[3];
+       mal->serr  = irqs[4];
+        ppc4xx_mal_reset(mal);
+        qemu_register_reset(&ppc4xx_mal_reset, mal);
+        ppc_dcr_register(env, MAL0_CFG,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_ESR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_IER,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCASR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCARR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXEOBISR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXDEIR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXCASR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXCARR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXEOBISR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXDEIR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCTP0R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCTP1R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCTP2R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCTP3R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXCTP0R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXCTP1R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RCBS0,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RCBS1,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+       /* For 440ep */
+        ppc_dcr_register(env, SDR0_MALTBL,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, SDR0_MALRBL,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, SDR0_MALTBS,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, SDR0_MALRBS,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+    }
+    return mal;
+}
+
+/*****************************************************************************/
+/* 
+ * I2C controller (SEE ALSO IN i2c.h before choice!!!)
+ *
+ * Control many device through uP resource.
+ * User could implement their device linked with this bus,
+ * specializing simple read(offset,value)/writec(offset,value)
+ * Only 7 bit address mode is supported.
+ *
+ * Difference known at me from 440EP/405GPr
+ *
+ *             440EP                           405GPr
+ * Base Addr    BASE4PERIPH+{0x700, 0x400}      EF600500
+ *
+ * MDCNTL/bit2  Enable general call             Reserved
+ * XTCNTLSS/bit6 Enable pulsed irq              Reserved
+ * DIRECTCNTL/bit5 SCLC                         SCC
+ *            bit7 MSCL                         MSC                
+ * INTR                                         Not exist
+ *              2 Bus Interface                 1 Bus Interface
+ * 
+ *
+ * Attached device, that must be indipendent from core implementation
+ * eeprom: data address with is 8/16/32 bits, use file as nv storage.
+ */
+#define I2C_VER2
+
+/* 
+ * This method simulate the insertion of a byte from the bus,
+ * and acquisition in uP registers.
+ *
+ * Return number of readed bytes
+ * FIX: Should be linked to OPB clock
+ */
+static uint32_t ppc4xx_i2c_pushb (ppc4xx_i2c_t *i2c, uint8_t val)
+{
+       uint32_t ret = 0;
+
+       assert(i2c->dataLen<=sizeof(i2c->data));
+       /* Check if space */
+       if (i2c->dataLen<sizeof(i2c->data)) {
+               i2c->data[i2c->dataLen] = val;
+               i2c->dataLen++;
+               /* Signal to uP that data exist */
+               i2c->sts |= 0x20;
+               ret=1;
+       } else {
+               /* Signal to uP that no more space exist */
+               i2c->sts |= 0x10;
+       }
+       /* Always read a byte, also need different read/write cursor? */
+       return ret;
+}
+
+static uint8_t ppc4xx_i2c_popb (ppc4xx_i2c_t *i2c)
+{
+       uint8_t ret = 0;
+
+       assert(i2c->dataLen<=sizeof(i2c->data));
+       if (i2c->dataLen>0) {
+               uint8_t i;
+               ret = i2c->data[0];
+               i2c->dataLen--;
+               for (i=0; i<(sizeof(i2c->data)-1); i++)
+                       i2c->data[i] = i2c->data[i+1];
+       }
+
+       if (i2c->dataLen<=0) {
+               /* Signal to uP that no more data exist */
+               i2c->sts &= ~0x30;
+       }
+       return ret;
+}
+
+static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr)
+{
+    ppc4xx_i2c_t *i2c;
+    uint32_t ret;
+
+    i2c = opaque;
+    switch (addr - i2c->base) {
+    case 0x00:
+#ifndef I2C_VER2  
+        ret = i2c->mdata;
+#else
+       ret = ppc4xx_i2c_popb(i2c);
+#endif
+        break;
+    case 0x02:
+        ret = i2c->sdata;
+        break;
+    case 0x04:
+        ret = i2c->lmadr;
+        break;
+    case 0x05:
+        ret = i2c->hmadr;
+        break;
+    case 0x06:
+        ret = i2c->cntl;
+        break;
+    case 0x07:
+        ret = i2c->mdcntl;
+        break;
+    case 0x08:
+        ret = i2c->sts;
+        break;
+    case 0x09:
+        ret = i2c->extsts;
+        break;
+    case 0x0A:
+        ret = i2c->lsadr;
+        break;
+    case 0x0B:
+        ret = i2c->hsadr;
+        break;
+    case 0x0C:
+        ret = i2c->clkdiv;
+        break;
+    case 0x0D:
+        ret = i2c->intrmsk;
+        break;
+    case 0x0E:
+        ret = i2c->xfrcnt;
+        break;
+    case 0x0F:
+        ret = i2c->xtcntlss;
+        break;
+    case 0x10:
+        ret = i2c->directcntl;
+        break;
+    case 0x11:
+       ret = i2c->intr;
+       break;
+    default:
+        ret = 0x00;
+        break;
+    }
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " %02" PRIx32 "\n", __func__, addr, ret);
+#endif
+
+    return ret;
+}
+
+
+/* Interaction with i2c.{h,c} module. Here we play the master role. */
+size_t ppc4xx_i2c_rw(i2c_bus *i2c, int dev_addr, uint8_t *data_addr, size_t 
len, char readfromdev) {
+       size_t ret;
+       int l;
+       ret = 0;
+#ifdef DEBUG_I2C
+        printf("%s: dev %x, len %d, %s\n", __func__, dev_addr, len, 
readfromdev?"read":"write");
+#endif
+       for (l=0; l<len; l++) {
+               if (l==0) {
+                       i2c_start_transfer(i2c, dev_addr, readfromdev); /* 
1=>RECV (from device) */
+               }
+               if (readfromdev) {
+                       data_addr[l] = i2c_recv(i2c);
+               } else {
+                       i2c_send(i2c, data_addr[l]);
+               }
+               if (l==len-1) {
+                       i2c_end_transfer(i2c); /* 1=>RECV (from device) */
+               }
+       }
+       ret = l;
+       return ret;
+}
+static void ppc4xx_i2c_writeb (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    ppc4xx_i2c_t *i2c;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value);
+#endif
+    i2c = opaque;
+    switch (addr - i2c->base) {
+    case 0x00:
+#ifndef I2C_VER2
+        i2c->mdata = value;
+        //        i2c_sendbyte(&i2c->mdata);
+#else
+       ppc4xx_i2c_pushb(i2c, (char)value);
+#endif
+        break;
+    case 0x02:
+        i2c->sdata = value;
+        break;
+    case 0x04:
+        i2c->lmadr = value;
+        break;
+    case 0x05:
+        i2c->hmadr = value;
+        break;
+    case 0x06:
+        i2c->cntl = value;
+#ifdef I2C_VER2
+       /* IIC0_CNTL (8bits)
+        * -----------------
+        * HMT  0x80    Halt master Transfer
+        * AMD  0x40    Address MoDe
+        * TCT  0x30    Transfer CounT
+        * RPST 0x08    RePeated STart
+        * CHT  0x04    CHain Tranfer
+        * RW   0x02    ReadWrite
+        * PT   0x01    PendingTransfer
+        *
+        * State/Action
+        * HMT RPSP     CHT     PT
+        * 0    -       -       0       No action
+        * 0    0       1       1       Start, Transfer, ACK on last byte, Pause
+        * 0    0       0       1                       NACK             , Stop
+        * 0    1       x       1                                        , Wait
+        * 1    x       x       x       NACK on current byte, Stop
+        */
+       if (value & 0x81) {
+               unsigned char len, lettu, aspe;
+               int addr;
+               size_t ret;
+               len = ((value >> 4) & 3) + 1;
+               lettu = (value & 2);
+               aspe = (value & 1);
+               addr = i2c->lmadr;
+               ret = 0;
+#ifdef DEBUG_I2C
+               printf("(I2C command len %d, %s, start %s pending transfer)\n", 
len, lettu?"READING":"WRITING", aspe?"only if not":"also if");
+#endif
+               assert(len<=sizeof(i2c->data));
+#ifdef I2C_USE_EXISTING
+               ret = ppc4xx_i2c_rw(i2c->bus, addr, i2c->data, len, lettu);
+#else
+               if (lettu && i2c->sl.readF) {
+                       ret = i2c->sl.readF(i2c->sl.opaque, addr, i2c->data, 
len);
+               }
+               if (!lettu && i2c->sl.writeF) {
+                       ret = i2c->sl.writeF(i2c->sl.opaque, addr, i2c->data, 
len);
+               }
+#endif
+#ifdef DEBUG_I2C
+               printf("User command return %d\n", ret);
+#endif
+               /* 
+                * on read from device  => Push bytes in uP buffer (simulate 
controller acquiring)
+                * on write ...         => Pop bytes from uP buffer (simulate 
device reading)
+                */
+               {
+                       unsigned int l;
+                       for (l=0; l<ret; l++) {
+                               lettu ?
+                                       ppc4xx_i2c_pushb(i2c, i2c->data[l]) :   
/* Produce data for uP */
+                                       ppc4xx_i2c_popb(i2c) ;                  
/* Consume data for uP */
+                       }
+
+               }
+       }
+#endif
+        break;
+    case 0x07:
+        i2c->mdcntl = value & 0xDF;
+        break;
+    case 0x08:
+        i2c->sts &= ~(value & 0x0A);
+        break;
+    case 0x09:
+        i2c->extsts &= ~(value & 0x8F);
+        break;
+    case 0x0A:
+        i2c->lsadr = value;
+        break;
+    case 0x0B:
+        i2c->hsadr = value;
+        break;
+    case 0x0C:
+        i2c->clkdiv = value;
+        break;
+    case 0x0D:
+        i2c->intrmsk = value;
+        break;
+    case 0x0E:
+        i2c->xfrcnt = value & 0x77;
+        break;
+    case 0x0F:
+        i2c->xtcntlss = value;
+        break;
+    case 0x10:
+        i2c->directcntl = value & 0x7;
+        break;
+    case 0x11:
+       i2c->intr = value;
+       break;
+    }
+}
+
+static uint32_t ppc4xx_i2c_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    ret = ppc4xx_i2c_readb(opaque, addr) << 8;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writew (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value);
+#endif
+    ppc4xx_i2c_writeb(opaque, addr, value >> 8);
+    ppc4xx_i2c_writeb(opaque, addr + 1, value);
+}
+
+static uint32_t ppc4xx_i2c_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    ret = ppc4xx_i2c_readb(opaque, addr) << 24;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writel (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value);
+#endif
+    ppc4xx_i2c_writeb(opaque, addr, value >> 24);
+    ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16);
+    ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8);
+    ppc4xx_i2c_writeb(opaque, addr + 3, value);
+}
+
+static CPUReadMemoryFunc *i2c_read[] = {
+    &ppc4xx_i2c_readb,
+    &ppc4xx_i2c_readw,
+    &ppc4xx_i2c_readl,
+};
+
+static CPUWriteMemoryFunc *i2c_write[] = {
+    &ppc4xx_i2c_writeb,
+    &ppc4xx_i2c_writew,
+    &ppc4xx_i2c_writel,
+};
+
+static void ppc4xx_i2c_reset (void *opaque)
+{
+    ppc4xx_i2c_t *i2c;
+
+    i2c = opaque;
+    i2c->mdata = 0x00;
+    i2c->sdata = 0x00;
+    i2c->cntl = 0x00;
+    i2c->mdcntl = 0x00;
+    i2c->sts = 0x00;
+    i2c->extsts = 0x00;
+    i2c->clkdiv = 0x00;
+    i2c->xfrcnt = 0x00;
+    i2c->directcntl = 0x0F;
+    i2c->intr = 0;
+}
+
+/* Qemu I2C infrastructure
+ * - why associate irq when binding to a slave?
+ */
+ppc4xx_i2c_t *ppc4xx_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                               target_phys_addr_t offset, qemu_irq irq)
+{
+    ppc4xx_i2c_t *i2c;
+
+    i2c = qemu_mallocz(sizeof(ppc4xx_i2c_t));
+    if (i2c != NULL) {
+        i2c->base = offset;
+        i2c->irq = irq;
+#ifdef I2C_USE_EXISTING
+        i2c->bus = i2c_init_bus();
+#else
+        if (sl) {
+                i2c->sl.readF = sl->readF;
+                i2c->sl.writeF = sl->writeF;
+                i2c->sl.opaque = sl->opaque;
+        }
+#endif
+        ppc4xx_i2c_reset(i2c);
+#ifdef DEBUG_I2C
+        printf("%s: offset " PADDRX "\n", __func__, offset);
+#endif
+        ppc4xx_mmio_register(env, mmio, offset, 0x011,
+                             i2c_read, i2c_write, i2c);
+        qemu_register_reset(ppc4xx_i2c_reset, i2c);
+    }
+    return i2c;
+}
Index: hw/ppc405.h
===================================================================
--- hw/ppc405.h (revision 5720)
+++ hw/ppc405.h (working copy)
@@ -84,9 +84,6 @@
                          CharDriverState *chr);
 /* On Chip Memory */
 void ppc405_ocm_init (CPUState *env, unsigned long offset);
-/* I2C controller */
-void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio,
-                      target_phys_addr_t offset, qemu_irq irq);
 /* General purpose timers */
 void ppc4xx_gpt_init (CPUState *env, ppc4xx_mmio_t *mmio,
                       target_phys_addr_t offset, qemu_irq irq[5]);
@@ -96,11 +93,15 @@
 CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
                          target_phys_addr_t ram_sizes[4],
                          uint32_t sysclk, qemu_irq **picp,
-                         ram_addr_t *offsetp, int do_init);
-CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
+                         ram_addr_t *offsetp, int do_init,
+                         ppc4xx_devsL *devsL);
+CPUState *ppc405xp_init (const char* cpu_model,
+                        target_phys_addr_t ram_bases[2],
                          target_phys_addr_t ram_sizes[2],
                          uint32_t sysclk, qemu_irq **picp,
-                         ram_addr_t *offsetp, int do_init);
+                         ram_addr_t *offsetp, int do_init,
+                         ppc4xx_devsL *devsL);
+                          
 /* IBM STBxxx microcontrollers */
 CPUState *ppc_stb025_init (target_phys_addr_t ram_bases[2],
                            target_phys_addr_t ram_sizes[2],
Index: hw/i2c.h
===================================================================
--- hw/i2c.h    (revision 5720)
+++ hw/i2c.h    (working copy)
@@ -87,4 +87,7 @@
 struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq);
 void lm832x_key_event(struct i2c_slave *i2c, int key, int state);
 
+/* eeprom, like 24LC256 */
+enum  iic_eeprom_cp {IIC_EEPROM_DEEP_COPY, IIC_EEPROM_SHALLOW_COPY};
+struct i2c_slave *iic_eeprom_init(i2c_bus *bus, int bus_width, size_t sizeB, 
char *data, enum iic_eeprom_cp);
 #endif
Index: hw/ppc4xx.h
===================================================================
--- hw/ppc4xx.h (revision 5720)
+++ hw/ppc4xx.h (working copy)
@@ -25,6 +25,8 @@
 #if !defined(PPC_4XX_H)
 #define PPC_4XX_H
 
+#include "i2c.h"
+
 /* PowerPC 4xx core initialization */
 CPUState *ppc4xx_init (const char *cpu_model,
                        clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
@@ -46,4 +48,77 @@
 qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
                        uint32_t dcr_base, int has_ssr, int has_vr);
 
+/* PowerPC 4xx Memory Access Layer */
+typedef struct ppc4xx_mal_t ppc4xx_mal_t;
+struct ppc4xx_mal_t {
+    qemu_irq txeob;
+    qemu_irq rxeob;
+    qemu_irq txde;
+    qemu_irq rxde;
+    qemu_irq serr;
+    uint32_t cfg;
+    uint32_t esr;
+    uint32_t ier;
+    uint32_t txcasr;
+    uint32_t txcarr;
+    uint32_t txeobisr;
+    uint32_t txdeir;
+    uint32_t rxcasr;
+    uint32_t rxcarr;
+    uint32_t rxeobisr;
+    uint32_t rxdeir;
+    uint32_t txctpr[4];
+    uint32_t rxctpr[2];
+    uint32_t rcbs[2];
+    uint32_t tbl;
+    uint32_t rbl;
+    uint32_t tbs;
+    uint32_t rbs;
+};
+ppc4xx_mal_t *ppc4xx_mal_init (CPUState *env, qemu_irq irqs[5]);
+
+/* PowerPC 4xx Ethernet Media Access Controller */
+void ppc4xx_emac_init (CPUState *env, ppc4xx_mmio_t *mmio, target_phys_addr_t 
offset, NICInfo *nic, ppc4xx_mal_t *mal);
+
+/* I2C controller */
+typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
+struct ppc4xx_i2c_t {
+    /* Master emulation */
+    target_phys_addr_t base;
+    qemu_irq irq;
+    uint8_t mdata;
+    uint8_t lmadr;
+    uint8_t hmadr;
+    uint8_t cntl;
+    uint8_t mdcntl;
+    uint8_t sts;
+    uint8_t extsts;
+    uint8_t sdata;
+    uint8_t lsadr;
+    uint8_t hsadr;
+    uint8_t clkdiv;
+    uint8_t intrmsk;
+    uint8_t xfrcnt;
+    uint8_t xtcntlss;
+    uint8_t directcntl;
+    uint8_t intr;
+
+    /* TODO This is treated like a FIFO with same OPB beat (now served 
immediately) */
+    uint8_t dataLen;
+    uint8_t data[4];
+
+    /* Main bus to which link all slave */
+    i2c_bus *bus;
+};
+
+ppc4xx_i2c_t *ppc4xx_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, 
target_phys_addr_t offset, qemu_irq irq);
+
+
+/* PowerPC4xx: let user configurate just builded machine
+ * Since no configuration is still present... */
+typedef struct ppc4xx_devsL ppc4xx_devsL;
+struct ppc4xx_devsL {
+       ppc4xx_i2c_t *i2c0;
+       ppc4xx_i2c_t *i2c1;
+};
 #endif /* !defined(PPC_4XX_H) */
Index: hw/iic_eeprom.c
===================================================================
--- hw/iic_eeprom.c     (revision 0)
+++ hw/iic_eeprom.c     (revision 0)
@@ -0,0 +1,209 @@
+/*
+ * PID eeprom via I2C
+ *
+ * Copyright (C) 2008 Lionetti Salvatore
+ * Written by Salvatore Lionetti <address@hidden>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <assert.h>
+#include "hw.h"
+#include "i2c.h"
+
+/*#define DEBUG_I2CE2P 1*/
+/* Setup
+ * =====
+ * s->i2c[0] = new()
+ * s->i2c[0]->slave.{event, recv, send} = ...
+ * s->i2c[0]->bus = i2c_init_bus()  new(i2c_bus)
+ * 
+ * i2c_set_slave_address(tmp105_init(s->i2c[0], irq))  i2c_slave_init(bus)
+ *
+ *
+ * Run-time
+ * ========
+ * slave->event()
+ * slave->recv()
+ * slave->send()
+ */
+struct iic_eeprom {
+    i2c_slave i2c;
+    
+    char addr_bytes;
+    char latch_addr;
+    uint32_t cur_addr;
+
+    uint8_t *data;
+    size_t dataB;
+};
+
+
+#ifdef DEBUG_I2CE2P
+#define DPRINTF(fmt, args...) do { printf("%s: " fmt , __func__, ##args); } 
while (0)
+#define BADF(fmt, args...) do { fprintf(stderr, "%s: " fmt , __func__, 
##args); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#define BADF(fmt, args...) do { fprintf(stderr, "iic_eeprom: error: " fmt , 
##args);} while (0)
+#endif
+
+
+static int iic_eeprom_read(i2c_slave *i2c)
+{
+    struct iic_eeprom *s = (struct iic_eeprom *) i2c;
+    uint8_t ret = 0xFF;
+
+    if (s->cur_addr<s->dataB) {
+           ret = s->data[s->cur_addr];
+    }
+    DPRINTF("read address@hidden", ret, s->cur_addr);
+    s->cur_addr++;
+    return (int)ret;
+}
+
+static int iic_eeprom_write(i2c_slave *i2c, uint8_t data)
+{
+    struct iic_eeprom *s = (struct iic_eeprom *) i2c;
+
+    if (s->latch_addr>0) {
+           s->cur_addr = (s->cur_addr<<8) | data;
+           s->latch_addr--;
+           DPRINTF("address %x\n", s->cur_addr);
+    } else {
+           DPRINTF("write address@hidden", data, s->cur_addr);
+           if (s->cur_addr<s->dataB) {
+                   s->data[s->cur_addr] = data;
+           }
+           s->cur_addr++;
+    }
+    return 0;
+}
+
+static const char* getEventDes(enum i2c_event ev) {
+       const char* ret="UNKNOWN COMMAND";
+       switch (ev) {
+           case I2C_START_SEND: ret = "START_SEND"; break;
+           case I2C_START_RECV: ret = "START_RECV"; break;
+           case I2C_FINISH:     ret = "FINISH"; break;
+           case I2C_NACK:       ret = "NACK"; break;
+       }
+       return ret;
+}
+static void iic_eeprom_event(i2c_slave *i2c, enum i2c_event event)
+{
+    struct iic_eeprom *s = (struct iic_eeprom *) i2c;
+
+    switch (event) {
+    case I2C_START_SEND:
+           /* Write sequence always start with address */
+           s->latch_addr = s->addr_bytes;
+           s->cur_addr = 0;
+    case I2C_START_RECV:
+    case I2C_FINISH:
+    case I2C_NACK:
+           break;
+    }
+    DPRINTF(" %s\n", getEventDes(event));
+}
+
+static void iic_eeprom_save(QEMUFile *f, void *opaque)
+{
+    struct iic_eeprom *s = (struct iic_eeprom *) opaque;
+
+    qemu_put_byte(f, s->latch_addr);
+    qemu_put_buffer(f, (uint8_t*)&s->cur_addr, sizeof(s->cur_addr));
+    
+    i2c_slave_save(f, &s->i2c);
+}
+
+static int iic_eeprom_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct iic_eeprom *s = (struct iic_eeprom *) opaque;
+
+    s->latch_addr = qemu_get_byte(f);
+    qemu_get_buffer(f, (uint8_t*)&s->cur_addr, sizeof(s->cur_addr));
+
+    i2c_slave_load(f, &s->i2c);
+    return 0;
+}
+
+void iic_eeprom_reset(i2c_slave *opaque)
+{
+    struct iic_eeprom *s = (struct iic_eeprom *) opaque;
+    s->latch_addr = 0;
+    s->cur_addr = 0;
+}
+
+/* Signal:
+ * - Clk given by master
+ * - Data shared
+ *   -  change when Clk high=>STATE CHANGE, start/stop command.
+ *   - !change when Clk high=>DATA
+ *   -  change when Clk low =>NO STATE CHANGE
+ *   - !change when Clk low =>NO STATE CHANGE
+ *
+ * A: BUS NOT BUSY
+ * Data = Clk = '1'
+ *
+ * B: START DATA TRANSFER
+ * Data '1'->'0' when Clk = '1'
+ *
+ * C: STOP DATA TRANSFER
+ * Data '0'->'1' when Clk = '1'
+ *
+ * D: DATA VALID
+ * Data stable when Clk = '1'
+ * 
+ * START/STOP transfer: data change during clk'high
+ * data change while clk
+ */
+/* 24LC256 Microchip:
+ * =================
+ * Addressing
+ *  bit7:4 1010
+ *  bit3:1 A2 A1 A0
+ *  bit0   1=>Read, 0=>Write
+ *  Ack bit
+ *
+ * 34XX02 Microchip, SPD (serial presence detect) for DIMM SDRAM
+ * Agree to JEDEC standard: www.jedec.org/download/search/4_01_02_00R9.PDF
+ */
+struct i2c_slave *iic_eeprom_init(i2c_bus *bus, int addr_width, size_t sizeB, 
char *data, enum iic_eeprom_cp cp)
+{
+    struct iic_eeprom *s;
+   
+    assert(data);
+    assert(addr_width==8 || addr_width==16 || addr_width==32);
+    s = (struct iic_eeprom *) i2c_slave_init(bus, 0, sizeof(struct iic_eeprom) 
+ (cp==IIC_EEPROM_DEEP_COPY?sizeB:0));
+
+    s->i2c.event = iic_eeprom_event;
+    s->i2c.recv = iic_eeprom_read;
+    s->i2c.send = iic_eeprom_write;
+
+    s->data = data;
+    s->dataB = sizeB;
+    s->addr_bytes = (addr_width>>=3);
+    if (cp == IIC_EEPROM_DEEP_COPY) {
+           s->data = (char*) &s[1];
+           memcpy(s->data, data, sizeB);
+    }
+    iic_eeprom_reset(&s->i2c);
+    DPRINTF(" Bus %p, width %d, sizeB %d, data %p\n, copy %s", bus, 
addr_width, sizeB, data, cp==IIC_EEPROM_DEEP_COPY?"DEEP":"SHALLOW");
+
+    register_savevm("I2CE2PROM", -1, 0, iic_eeprom_save, iic_eeprom_load, s);
+
+    return &s->i2c;
+}









reply via email to

[Prev in Thread] Current Thread [Next in Thread]