[Top][All Lists]
[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;
+}
- [Qemu-devel] [PATCH 1/3] PPC4xx IIC and MAL,
Salvatore Lionetti <=