[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] PowerPC 4xx enhacement
From: |
Salvatore Lionetti |
Subject: |
Re: [Qemu-devel] PowerPC 4xx enhacement |
Date: |
Fri, 21 Nov 2008 01:53:20 +0000 (GMT) |
Source modified
===============
- code factoring for ppc405GPr, ppc405EP, ppc405GPe
- reorganization in i2c code, with possibility of board customization callback
- new board added for 'DHT Walnut board', fw in pc-bios/walnut_uboot.bin
- cfi flash now support 'buffer mode', write N {byte, halfword, word}
consecutively.
- emac/mal now work with vlan mode
Board Walnut:
=============
http://elinux.org/DHT-Walnut-Flameman
CPU PowerPC 405 GPe running at 266Mhz
LAN On-chip 405GP ethernet, namely emac/mal
ROM 512k of boot flash, AMD 29LV040B
PID eeprom via i2c
Full Tested (eth, flash, pid)
=============================
- u-boot 1.1.6 on walnut board (with few patch, see ppc405_board.c)
- OSE on proprietary NSN 4G radio module
- Can anyone test ref405ep and taihu?
P.S:
I've tryed to have patch for bin file but no luck
Since i can not version file, does diff support binary file?does attachment
work?
Index: Makefile.target
===================================================================
--- Makefile.target (revision 5720)
+++ Makefile.target (working copy)
@@ -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 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: osdep.c
===================================================================
--- osdep.c (revision 5720)
+++ osdep.c (working copy)
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/statvfs.h>
#endif
+#include <assert.h>
#include "qemu-common.h"
#include "sysemu.h"
@@ -310,3 +311,49 @@
fcntl(fd, F_SETFL, f | O_NONBLOCK);
}
#endif
+
+void *qemu_mmap(void * start, size_t length, int prot, int flags, int fd,
off_t offset) {
+ void *ret;
+#ifndef _WIN32
+ ret = mmap(start, length, prot, flags, fd, offset);
+#else
+ { /* TO TEST!!! */
+ static char name[15];
+ static char ind=0;
+ HANDLE fd_map;
+ LPVOID fd_buf;
+ char* buf;
+
+ assert(fd!=INVALID_HANDLE_VALUE);
+
+ snprintf(name, 15, "qemu_mmap%d", ind++);
+ fd_map = CreateFileMapping(fd,
+ NULL, /* Security attr */
+ PAGE_READWRITE,
+ 0, TOTAL_SIZE,
+ name);
+
+ fd_buf = MapViewOfFile(fd_map,
+ FILE_MAP_ALL_ACCESS,
+ 0, 0, /* Offset */
+ TOTAL_SIZE);
+ assert(fd_buf);
+ ret = fd_buf;
+
+ }
+#endif
+ return ret;
+}
+int qemu_munmap(void *start, size_t length) {
+ int ret;
+#ifndef _WIN32
+ ret = munmap(start, length);
+#else
+ { /* TO TEST!!! */
+ UnmapViewOfFile(start);
+ /*CloseHandle(fd_map);
+ CloseHandle(fd);*/
+ }
+#endif
+ return ret;
+}
Index: target-ppc/machine.c
===================================================================
--- target-ppc/machine.c (revision 5720)
+++ target-ppc/machine.c (working copy)
@@ -8,6 +8,7 @@
qemu_register_machine(&prep_machine);
qemu_register_machine(&ref405ep_machine);
qemu_register_machine(&taihu_machine);
+ qemu_register_machine(&walnut_machine);
}
void cpu_save(QEMUFile *f, void *opaque)
Index: qemu-common.h
===================================================================
--- qemu-common.h (revision 5720)
+++ qemu-common.h (working copy)
@@ -152,4 +152,11 @@
/* Force QEMU to stop what it's doing and service IO */
void qemu_service_io(void);
+/* KR function prototype. */
+typedef size_t KRHandler(int fd, char* buf, size_t size);
+
+/* mmap like function
+ * (cygwin seem !have aio yet so no linux env under Winzozz) */
+void *qemu_mmap(void * start, size_t length, int prot, int flags, int fd,
off_t offset);
+int qemu_munmap(void *start, size_t length);
#endif
Index: hw/ppc405_boards.c
===================================================================
--- hw/ppc405_boards.c (revision 5720)
+++ hw/ppc405_boards.c (working copy)
@@ -206,7 +206,7 @@
#ifdef DEBUG_BOARD_INIT
printf("%s: register cpu\n", __func__);
#endif
- env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &sram_offset,
+ env = ppc405xp_init("405ep", ram_bases, ram_sizes, 33333333, &pic,
&sram_offset,
kernel_filename == NULL ? 0 : 1);
/* allocate SRAM */
#ifdef DEBUG_BOARD_INIT
@@ -353,7 +353,6 @@
printf("bdloc %016lx %s\n",
(unsigned long)bdloc, (char *)(phys_ram_base + bdloc));
}
-
QEMUMachine ref405ep_machine = {
.name = "ref405ep",
.desc = "ref405ep",
@@ -361,6 +360,349 @@
.ram_require = (128 * 1024 * 1024 + 4096 + 512 * 1024 + BIOS_SIZE) |
RAMSIZE_FIXED,
};
+/*
+ * Walnut board
+ *
+ * Starting point from official uboot 1.1.6 with following patch:
+ * - compilation error: cmd_bootm.c:470 manually expand #if
+ * - mac address not in nvram: include/configs/walnut.h add
"ethaddr=52:54:00:12:34:56\0" in CONFIG_EXTRA_ENV_SETTING
+ * - remove trailer from recv packet(fcs?): cpu/ppc4xx/4xx_enet.c:1478 call
NetReceive with 'length' as 2nd parameter.
+ */
+/* Addedum related to 405GP: is it only for such device? */
+static target_ulong walnut_dcr_read (void *opaque, int dcrn)
+{
+ target_ulong ret=0;
+ switch (dcrn) {
+ case 0xAA: /* CPCO_ECR */
+ break;
+ case 0xB0: /* CPC0_PLLMR */
+ /* |--> {ForwardA,
Backward} Divisor
+ * ---- |--> Opb
+ * ---> | x2 |-|--> ExtBus
+ * ---- | ----
+ * CPU ---> | /4 | ---> PLB ------------> PCI
+ * Clock ----
+ */
+ ret = -2 << 29;/* Forward divisor is 2 */
+ ret |= 2 << 25; /* Backward divisor is 2 */
+ ret |= 3 << 17; /* Cpu/Plb is 4 */
+ ret |= 0 << 13; /* Pci/Plb is 1 */
+ ret |= 0 << 11; /* ExtBus/Plb is 2 */
+ ret |= 1 << 15; /* Opb/Plb is 2 */
+ break;
+ case 0xB1: /* CPC0_CR0 */
+ break;
+ case 0xB2: /* CPC0_CR1 */
+ break;
+ case 0xB4: /* CPC0_PSR: For same uP model, could be different!
*/
+ break;
+ default:
+ break;
+ }
+/* printf("walnut_dcr [%x] => %x\n", dcrn, ret);*/
+ return ret;
+}
+static void walnut_dcr_write (void *opaque, int dcrn, target_ulong val)
+{
+/* printf("walnut_dcr [%x] <= %x\n", dcrn, val);*/
+}
+
+/*
+ * I2C Customization
+ *
+ * A file.
+ */
+static char PID_content[128]; /* If no file present */
+static uint32_t PID_cursor;
+size_t PID_read(int addr, char *buf, size_t len) {
+ int ret;
+ ret = len;
+ if (len+PID_cursor>128)
+ len = 128 - PID_cursor;
+ memcpy(buf, &PID_content[PID_cursor], len);
+
+#if 0
+ {
+ int i;
+ printf("PID_Read dev(%x) len %d offs %d =>(", addr, ret, PID_cursor);
+ for (i=0; i<ret; i++) {
+ printf(" %x,", buf[i]);
+ }
+ printf(") ret %d\n", ret);
+ }
+#endif
+ return ret;
+}
+size_t PID_write(int addr, char *buf, size_t len) {
+ int ret;
+ ret = len;
+ /* buf = {offset} if write to set position (a read'll
follow)
+ * = {offset,data0, data1 ...} if write data different from
position */
+ if (len>0) {
+ PID_cursor = buf[0];
+ len--;
+ if (len>0) {
+ if (len+PID_cursor>128)
+ len = 128 - PID_cursor;
+ memcpy(&PID_content[PID_cursor], buf+1, len);
+ }
+ }
+#if 0
+ {
+ int i;
+ printf("PID_Write dev(0x%x) len %d, off %d <=(", addr, ret, PID_cursor);
+ for (i=0; i<ret; i++) {
+ printf(" %x,", buf[i]);
+ }
+ printf(")\n");
+ }
+#endif
+
+ return ret;
+}
+static void walnut_init (ram_addr_t ram_size, int vga_ram_size,
+ const char *boot_device, DisplayState *ds,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ ppc4xx_bd_info_t bd;
+ CPUPPCState *env;
+ qemu_irq *pic;
+ ram_addr_t sram_offset, bios_offset, bdloc;
+ target_phys_addr_t ram_bases[2], ram_sizes[2];
+ target_ulong sram_size, bios_size;
+ //int phy_addr = 0;
+ //static int phy_addr = 1;
+ target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+ int linux_boot;
+ int fl_idx, fl_sectors, len;
+ int ppc_boot_device = boot_device[0];
+ int index;
+
+ /* XXX: fix this */
+ ram_bases[0] = 0x00000000;
+ ram_sizes[0] = 0x08000000;
+ ram_bases[1] = 0x00000000;
+ ram_sizes[1] = 0x00000000;
+ ram_size = 128 * 1024 * 1024;
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register cpu\n", __func__);
+#endif
+ env = ppc405xp_init("405GPe", ram_bases, ram_sizes, 33333333, &pic,
&sram_offset,
+ kernel_filename == NULL ? 0 : 1);
+ /* Customize some dcr */
+ ppc_dcr_register(env, 0xAA/* CPC0_ECR */, NULL, &walnut_dcr_read,
&walnut_dcr_write);
+ ppc_dcr_register(env, 0xB0/* CPC0_PLLMR */, NULL, &walnut_dcr_read, NULL);
+ ppc_dcr_register(env, 0xB1/* CPC0_CR0 */, NULL, &walnut_dcr_read,
&walnut_dcr_write);
+ ppc_dcr_register(env, 0xB2/* CPC0_CR1 */, NULL, &walnut_dcr_read,
&walnut_dcr_write);
+ ppc_dcr_register(env, 0xB4/* CPC0_PSR */, NULL, &walnut_dcr_read, NULL);
+
+ /* Customize I2C access */
+ {
+ extern KRHandler* readF;
+ extern KRHandler* writeF;
+
+ /* PID */
+ //load_init_image("pid.bin", NULL, 256, 0xff);
+ int PID_fd;
+ memset(PID_content, 0, 128);
+ if ((PID_fd=open("pid.bin", O_RDWR | O_BINARY, 0666))>=0) { /*"r+b");*/
+ int n = read(PID_fd, PID_content, 128);
+ if (n<0) {
+ printf("Error reading file pid.bin (ret %d)\n", n);
+ } else if (n<128) {
+ printf("Warning reading file pid.bin: only %d/128 bytes
loaded\n", n);
+ }
+ close(PID_fd);
+ }
+ if (PID_fd<0) {
+ /* Built in eeprom */
+ printf("Warning using builtin pid content!\n");
+ PID_content[2] = 4; /* Magic word, use sdram */
+ PID_content[3] = 12; /* Row word, use sdram */
+ PID_content[4] = 10; /* Col word, use sdram */
+ PID_content[5] = 1; /* 1 bank */
+ PID_content[6] = 32; /* Module width */
+ PID_content[31] = 0x10; /* How many 4MB is long */
+ PID_content[127]= 0 | 2 /* Cas latency */;
+ }
+
+ readF = &PID_read;
+ writeF = &PID_write;
+ }
+ /* allocate SRAM */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register SRAM at offset %08lx\n", __func__, sram_offset);
+#endif
+ /* Last 48 (max 128) bytes) used for bd info */
+ sram_size = 8 * 1024;
+ cpu_register_physical_memory(0x40000000, sram_size,
+ sram_offset | IO_MEM_RAM);
+ /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register BIOS\n", __func__);
+#endif
+ bios_offset = sram_offset + sram_size;
+ fl_idx = 0;
+#ifdef USE_FLASH_BIOS
+ index = drive_get_index(IF_PFLASH, 0, fl_idx);
+ if (index != -1) {
+ bios_size = bdrv_getlength(drives_table[index].bdrv);
+ fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+ printf("Register parallel flash %d size " ADDRX " at offset %08lx "
+ " addr " ADDRX " '%s' %d\n",
+ fl_idx, bios_size, bios_offset, -bios_size,
+ bdrv_get_device_name(drives_table[index].bdrv), fl_sectors);
+#endif
+ pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+ drives_table[index].bdrv, 65536, fl_sectors, 1,
+ 2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA);
+ fl_idx++;
+ } else
+#endif
+ {
+ char buf[1024];
+ ram_addr_t flash_offset;
+ target_ulong flash_size;
+
+ flash_offset = bios_offset;
+ flash_size = 512*1024;
+#ifdef DEBUG_BOARD_INIT
+ printf("Load BIOS from file\n");
+#endif
+ if (bios_name == NULL)
+ bios_name = BIOS_FILENAME;
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
+ bios_size = get_image_size(buf);
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+ exit(1);
+ }
+ bios_size = (bios_size + 0xfff) & ~0xfff;
+#ifdef DEBUG_BOARD_INIT
+ printf("Loading bios@" ADDRX " %d bytes\n", (uint32_t)(-bios_size),
bios_size);
+#endif
+#if 1
+ pflash_cfi02_register((uint32_t)(-flash_size), flash_offset,
+ NULL, 65536 /*sector len*/, flash_size/65536 /*
nblocks */, 1,
+ 1 /* width */, 0x0001/* AMD */, 0x4F/*
Am29LV040B */, 0x0000, 0x0000, 0x555/* unlock addrs */, 0x2AA);
+#else
+ cpu_register_physical_memory((uint32_t)(-flash_size),
+ flash_size, flash_offset | IO_MEM_ROM);
+#endif
+
+ bios_size = load_image_targphys(buf, (-bios_size), BIOS_SIZE/* max sz
*/);
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+ exit(1);
+ }
+ bios_size = flash_size;
+ }
+ bios_offset += bios_size;
+ /* Register FPGA */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register FPGA\n", __func__);
+#endif
+ ref405ep_fpga_init(0xF0300000);
+ /* Register NVRAM */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register NVRAM\n", __func__);
+#endif
+ m48t59_init(NULL, 0xF0000000, 0, 8192, 8);
+ /* Load kernel */
+ linux_boot = (kernel_filename != NULL);
+ if (0) {
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: load kernel\n", __func__);
+#endif
+ memset(&bd, 0, sizeof(bd));
+ bd.bi_memstart = 0x00000000;
+ bd.bi_memsize = ram_size;
+ bd.bi_flashstart = -bios_size;
+ bd.bi_flashsize = -bios_size;
+ bd.bi_flashoffset = 0;
+ bd.bi_sramstart = 0xFFF00000;
+ bd.bi_sramsize = sram_size;
+ bd.bi_bootflags = 0;
+ bd.bi_intfreq = 133333333;
+ bd.bi_busfreq = 33333333;
+ bd.bi_baudrate = 115200;
+ bd.bi_s_version[0] = 'Q';
+ bd.bi_s_version[1] = 'M';
+ bd.bi_s_version[2] = 'U';
+ bd.bi_s_version[3] = '\0';
+ bd.bi_r_version[0] = 'Q';
+ bd.bi_r_version[1] = 'E';
+ bd.bi_r_version[2] = 'M';
+ bd.bi_r_version[3] = 'U';
+ bd.bi_r_version[4] = '\0';
+ bd.bi_procfreq = 133333333;
+ bd.bi_plb_busfreq = 33333333;
+ bd.bi_pci_busfreq = 33333333;
+ bd.bi_opbfreq = 33333333;
+ bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001);
+ env->gpr[3] = bdloc;
+ kernel_base = KERNEL_LOAD_ADDR;
+ /* now we can load the kernel */
+ kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
+ if (kernel_size < 0) {
+ fprintf(stderr, "qemu: could not load kernel '%s'\n",
+ kernel_filename);
+ exit(1);
+ }
+ printf("Load kernel size " TARGET_FMT_ld " at " TARGET_FMT_lx
+ " %02x %02x %02x %02x\n", kernel_size, kernel_base,
+ *(char *)(phys_ram_base + kernel_base),
+ *(char *)(phys_ram_base + kernel_base + 1),
+ *(char *)(phys_ram_base + kernel_base + 2),
+ *(char *)(phys_ram_base + kernel_base + 3));
+ /* load initrd */
+ if (initrd_filename) {
+ initrd_base = INITRD_LOAD_ADDR;
+ initrd_size = load_image(initrd_filename,
+ phys_ram_base + initrd_base);
+ if (initrd_size < 0) {
+ fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+ } else {
+ initrd_base = 0;
+ initrd_size = 0;
+ }
+ env->gpr[4] = initrd_base;
+ env->gpr[5] = initrd_size;
+ ppc_boot_device = 'm';
+ if (kernel_cmdline != NULL) {
+ len = strlen(kernel_cmdline);
+ bdloc -= ((len + 255) & ~255);
+ memcpy(phys_ram_base + bdloc, kernel_cmdline, len + 1);
+ env->gpr[6] = bdloc;
+ env->gpr[7] = bdloc + len;
+ } else {
+ env->gpr[6] = 0;
+ env->gpr[7] = 0;
+ }
+ env->nip = KERNEL_LOAD_ADDR;
+ } else {
+ env->nip = 0xFFFFFFFC;
+ }
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: Done\n", __func__);
+#endif
+ /*printf("bdloc %016lx %s\n",
+ (unsigned long)bdloc, (char *)(phys_ram_base + bdloc));*/
+}
+QEMUMachine walnut_machine = {
+ .name = "walnut",
+ .desc = "DHT Walnut board, based on ppc405GPe",
+ .init = walnut_init,
+ .ram_require = (128 * 1024 * 1024 + 4096 + 512 * 1024 + BIOS_SIZE) |
RAMSIZE_FIXED,
+};
+
/*****************************************************************************/
/* AMCC Taihu evaluation board */
/* - PowerPC 405EP processor
@@ -530,7 +872,7 @@
#ifdef DEBUG_BOARD_INIT
printf("%s: register cpu\n", __func__);
#endif
- env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &bios_offset,
+ env = ppc405xp_init("405ep", ram_bases, ram_sizes, 33333333, &pic,
&bios_offset,
kernel_filename == NULL ? 0 : 1);
/* allocate and load BIOS */
#ifdef DEBUG_BOARD_INIT
Index: hw/emac.c
===================================================================
--- hw/emac.c (revision 0)
+++ hw/emac.c (revision 0)
@@ -0,0 +1,797 @@
+/*
+ * QEMU EMAC emulation
+ *
+ * Copyright (c) 2008, Lionetti Salvatore address@hidden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This module provide an emulation for ethernet onchip controller on ppc4xx
cpu.
+ * Tested on
+ * - emulator of a NSN proprietary board, for 4G
+ * - walnut board/u-boot-1.1.6 (whith some patch)
+ *
+ * TODO:
+ * - >1 {tx, rx} channel
+ * - can_receive() and buffer_full() too simple.
+ */
+#include "hw.h"
+#include "ppc.h"
+#include "ppc405.h"
+#include "pc.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "net.h"
+
+/*#define DEBUG_EMAC*/
+#ifdef DEBUG_EMAC
+#define DPRINT(fmt, args...) \
+ do { printf("%" PRIu64 " %s: " fmt , qemu_get_clock(rt_clock), __func__,
##args); } while (0)
+#else
+#define DPRINT(fmt, args...)
+#endif
+
+/*
+ * Redefined because if !exist, linker gives a warning but produce qemu,
+ * but on execution this call cause problem
+ * (could be cygwin & mingw cohesistence?)
+ */
+#if (defined(WORDS_BIGENDIAN) && defined(TARGET_WORDS_BIGENDIAN)) ||
((!defined(WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN)))
+#if 0
+static unsigned long int htonl(unsigned long int hostlong);
+static unsigned short int htons(unsigned short int hostshort);
+#endif
+static unsigned long int ntohl(unsigned long int ing) {
+ return ing;
+}
+static unsigned short int ntohs(unsigned short int ing) {
+ return ing;
+}
+#else
+static unsigned long int ntohl(unsigned long int ing) {
+ unsigned char tmp;
+ unsigned char* tmpp = (unsigned char*)&ing;
+ tmp=tmpp[0]; tmpp[0]=tmpp[3]; tmpp[3]=tmp;
+ tmp=tmpp[1]; tmpp[1]=tmpp[2]; tmpp[2]=tmp;
+ return *(unsigned long int*)tmpp;
+}
+static unsigned short int ntohs(unsigned short int ing) {
+ return ((ing&0xFF)<<8) | ((ing&0xFF00)>>8);
+}
+#endif
+
+/* qemu initialization:
+ *
+ * parse command line: call net_client_init() for each -net, either for {if,
collision domain} options.
+ * ==========
================
+ * IF MAC=... <==== Vlan{Id,Ptr} ====>
COLLISION DOMAIN (mean N-1 other IF MAC=...)
+ * ==========
================
+ * -net nic[,...]: fill field onto nd_table[]
{MAC(cl|auto), model, vlanPtr=f(vlanId)}
+ * vlanPtr=f(vlanId)->guest++
+ * -net tap[,...]: vlanPtr=f(vlanId)->host ++
+ * tap_win32_init(vlanPtr,
"ifname=tap..."):
+ *
qemu_new_vlan_client(vlanPtr,tap_receive, tap* opaque) RECV
+ *
qemu_add_wait_object(tap_sem, tap_w32_send, tap* opaque) SEND
+ *
+ * For each vlan created,
+ * exit if no GUEST & some HOST
+ * warn if some GUEST & no HOST
+ *
+ * start machine: Es ppc (also pc use n2000) call machine->init():
+ * isa_ne2000_init(base, irqno, &nd_table[i])
+ * register_ioport_write(base + ...,
ne2000_asic_ioport_write, opaque NE2000State*); SEND
+ * qemu_new_vlan_client(nd->vlan, ne2000_receive,
ne2000_can_receive, opaque NE2000State*) RECV
+ *
+ * Done!!!
+ *
+ * qemu runtime scenario:
+ *
+ * packet send from HOST: a signal (after exec() cycle) is sent to
tap_sem => tap_w32_send() => tap_win32_read()
+ * if some bytes returned => qemu_send_packet() =>
send to all 'client' (better peer) of
+ * such vlan, different from itself =>
ne2000_receive()
+ *
+ * packet send from GUEST: in machine code we call qemu_send_packet() =>
(prec) => tap_receive() => tap_w32_write()
+ *
+ *
+ * So onto VLAN actors always call qemu_send_packet() that dispatch packet to
all peer attached to same vlan.
+ *
+ */
+/* PPC405 layer 2, reversed MII mode:
+ *
+ * address@hidden already mapped.
+ * Configuration RW:
+ *
+ * Read(ind, data):
+ * [EMAC0_STACR] <= (STACR_STAC_R | ind)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ * [EMAC0_STACR] => >>16 => data
+ *
+ * Write(ind, data)
+ * [EMAC0_STACR] <= (STACR_STAC_W | ind | data<<16)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ *
+ * Physical access:
+ * Read(ind_phy, ind_reg, data)
+ * [EMAC0_STACR] <= (STACR_STAC_W | TANTOS_REG_MIIAC | (ind_reg&0x1F |
OP_READ | (ind_phy&0x1F)<<5))>>16
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ *
+ * Verify:
+ * [EMAC0_STACR] <= (STACR_STAC_R | TANTOS_REG_MIIRD)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ * [EMAC0_STACR] => data
+ * data & STACR_PHYE should be 0
+ * data=data>>16
+ *
+ * Tantos Stub Layer: (needed?)
+ *
+ * From mal we need
+ * - MAL0_TXCTPxR
+ * - MAL0_RXCTPxR
+ * - MAL0_RCBS0
+ */
+/* TODO: need interaction between device!
+ * very difficult since all struct is in .c file */
+extern uint32_t txctpr[4];
+extern uint32_t rxctpr[2];
+extern uint32_t rcbs[2];
+extern uint32_t *rxeobisr; /* With namespace, use & to automatize
correlation.*/
+extern uint32_t *txeobisr;
+// For PPC405
+#define EMAC0_BASE 0xEF600800
+#define EMAC0_STACR_DISP 0x35
+#define EMAC0_STACR (EMAC0_BASE + EMAC0_STACR_DISP) /* 4 byte addressing
*/
+#define STACR_OC 0x00008000 /* Occupied flag */
+#define STACR_PHYE 0x00004000
+#define STACR_STAC_W 0x00002000
+#define STACR_STAC_R 0x00001000
+
+#define TANTOS_REG_MIIAC 0x120 /// TANTOS3G MII indirect acess
registers
+#define TANTOS_REG_MIIWD 0x121
+#define TANTOS_REG_MIIRD 0x122
+#define OP_WRITE 0x0400
+#define OP_READ 0x0800
+#define MBUSY 0x8000
+
+/* WORDS_BIGENDIAN = FALSE su HOST i386, GUEST ppc
+ * per cui e' l'architetura HOST
+ */
+struct EmacMalRxDes {
+#ifndef WORDS_BIGENDIAN
+ union {
+ struct { /* Mal */
+ unsigned int emac1_nu : 2;
+ unsigned int bit5_intr : 1;
+ unsigned int bit4_first : 1;
+ unsigned int bit3_last : 1;
+ unsigned int bit2_contm : 1;
+ unsigned int bit1_wrap : 1;
+ unsigned int bit0_empty : 1;
+ unsigned int emac2_nu : 8;
+ } __attribute__ ((packed)) mal;
+ struct { /* Status: Read access, error cause */
+ unsigned int bit7_pausepacket : 1;
+ unsigned int bit6_overrun : 1;
+ unsigned int mal_nu : 6;
+ unsigned int bit15_inrange : 1;
+ unsigned int bit14_outrange : 1;
+ unsigned int bit13_longpacket : 1;
+ unsigned int bit12_fcs : 1;
+ unsigned int bit11_alignment : 1;
+ unsigned int bit10_shortevent : 1;
+ unsigned int bit9_runtpacket : 1;
+ unsigned int bit8_badpacket : 1;
+ } __attribute__ ((packed)) emac_errstatus;
+ } __attribute__ ((packed));
+#else
+#error "Host endianism BUG: To Test!!!"
+#endif
+ unsigned short len;
+ unsigned char* buf;
+} __attribute__ ((packed)); /* Host endianism, to be converted */
+
+struct EmacMalTxDes {
+#ifndef WORDS_BIGENDIAN
+ /* IN A HALF-WORD (16bits)
+ * position position
+ * in bitfield in value
+ * from high from MSb
+ * =========================
+ * 0 8
+ * 1 9
+ * 2 10
+ * 3 11
+ * 4 12
+ * 5 13
+ * 6 14
+ * 7 15
+ * 8 0
+ * 9 1
+ * 10 2
+ * 11 3
+ * 12 4
+ * 13 5
+ * 14 6
+ * 15 7
+ *
+ * ===HOST LE, TARGET BE===
+ * IN A BYTE (8bits)
+ *
+ * IN A HALF-WORD (16bits)
+ * 0-7 8-15
+ * 8-15 0-7
+ */
+ union {
+ struct { /* Mal */
+ unsigned int emac1_nu : 2;
+ unsigned int bit5_intr : 1;
+ unsigned int bit4_resv : 1;
+ unsigned int bit3_last : 1;
+ unsigned int bit2_contm : 1;
+ unsigned int bit1_wrap : 1;
+ unsigned int bit0_ready : 1;
+ unsigned int emac2_nu : 8;
+ } __attribute__ ((packed)) mal;
+ struct { /* Status: Read access, error cause */
+ unsigned int bit7_badpacket : 1;
+ unsigned int bit6_badfsc : 1;
+ unsigned int mal_nu : 6;
+ unsigned int bit15_sqe : 1;
+ unsigned int bit14_underrun : 1;
+ unsigned int bit13_singlecoll : 1;
+ unsigned int bit12_multiplecoll : 1;
+ unsigned int bit11_latecoll : 1;
+ unsigned int bit10_excessivecoll : 1;
+ unsigned int bit9_excessivedeferral : 1;
+ unsigned int bit8_lossofcarrier : 1;
+ } __attribute__ ((packed)) emac_errorstatus;
+ struct { /* Control: Write access */
+ unsigned int bit7_generatepad : 1;
+ unsigned int bit6_generatefcs : 1;
+ unsigned int mal_nu : 6;
+ unsigned int emac_nu : 4;
+ unsigned int bit11_vlantag_replace : 1;
+ unsigned int bit10_vlantag_insert : 1;
+ unsigned int bit9_sourceaddr_insert : 1;
+ unsigned int bit8_sourceaddr_replace: 1;
+ } __attribute__ ((packed)) emac_control;
+ };
+#else
+#error "Host endianism BUG: To Test!!!"
+#endif
+ unsigned short len;
+ unsigned char* buf;
+}__attribute__ ((packed)); /* Host endianism, to be converted */
+
+/* Controlo Register definition */
+struct EmacRegs {
+#if 0
+#ifndef WORDS_BIGENDIAN
+ struct Emac0_mr0 {
+ unsigned int ;
+ } __attribute__((packed));
+#else
+#error "Host endianism BUG: To Test!!!"
+#endif
+#else
+ /* 0 */
+ uint32_t mr0;
+ uint32_t mr1;
+ uint32_t tmr0;
+ uint32_t tmr1;
+ uint32_t rmr;
+ uint32_t isr;
+ uint32_t isre;
+ uint32_t iahr;
+ uint32_t ialr;
+ uint32_t vtpid;
+ /* 10 */
+ uint32_t vtci;
+ uint32_t ptr;
+ uint32_t iaht1;
+ uint32_t iaht2;
+ uint32_t iaht3;
+ uint32_t iaht4;
+ uint32_t gaht1;
+ uint32_t gaht2;
+ uint32_t gaht3;
+ uint32_t gaht4;
+ /* 20 */
+ uint32_t lsah;
+ uint32_t lsal;
+ uint32_t ipgvr;
+ uint32_t stacr;
+ uint32_t trtr;
+ uint32_t rwmr;
+ uint32_t octx;
+ uint32_t ocrx;
+ /* 28 reg */
+
+#define RSTA mr0 & 0x20000000
+#define TXEN mr0 & 0x10000000
+#define RXEN mr0 & 0x08000000
+#endif
+} __attribute__ ((packed));
+
+typedef struct ppc4xx_emac_t ppc4xx_emac_t;
+struct ppc4xx_emac_t {
+ /* Guest related */
+ target_phys_addr_t base;
+ NICInfo nic;
+ /* To remove, already defined in mal */
+ qemu_irq mal_irqs_txeob;
+ qemu_irq mal_irqs_rxeob;
+ qemu_irq mal_irqs_txerr;
+ qemu_irq mal_irqs_rxerr;
+ qemu_irq mal_irqs_syserr;
+
+ struct EmacRegs reg, _reg;
+
+ struct EmacMalTxDes* tx;
+ struct EmacMalRxDes* rx;
+
+ int txPos, rxPos;
+ int txNum, rxNum;
+
+ int rxLostNum, rxLostLimit;
+
+ /* Host related */
+ VLANClientState *vc;
+ QEMUTimer* tx_timer;
+};
+
+#if 0
+#define EMACMAL_EMPTY 0x8000
+#define EMACMAL_WRAP 0x8000
+#define EMACMAL_EMPTY 0x8000
+#define EMACMAL_EMPTY 0x8000
+void EmacMalDes_readFromTarget(struct EmacMalDes* host, struct EmacMalDes*
guest) {
+
+ host->status = ntohs(guest->status);
+ host->len = ntohs(guest->len);
+ host->buf = htol(guest->buf);
+}
+void EmacMalDes_writeToTarget(struct EmacMalDes* host, struct EmacMalDes*
guest) {
+}
+#endif
+void EmacMalRxDes_dump(struct EmacMalRxDes* des) {
+#ifdef DEBUG_EMAC
+ unsigned char* tdes = (unsigned char*) ((unsigned char*)des -
phys_ram_base);
+ printf("address@hidden,buf%p,empty%d wrap%d contm %d last%d first%d
intr%d\n",
+ tdes, ntohs(des->len), (unsigned char*) ntohl((unsigned
long int)des->buf),
+ des->mal.bit0_empty, des->mal.bit1_wrap,
des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_first,
des->mal.bit5_intr);
+#endif
+}
+void EmacMalTxDes_dump(struct EmacMalTxDes* des) {
+#ifdef DEBUG_EMAC
+ unsigned char* tdes = (unsigned char*)((unsigned char*)des -
phys_ram_base);
+ printf("address@hidden,buf%p,ready%d wrap%d contm %d last%d first%d
intr%d\n",
+ tdes, ntohs(des->len), (unsigned char*)ntohl((unsigned
long int)des->buf),
+ des->mal.bit0_ready, des->mal.bit1_wrap,
des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_resv,
des->mal.bit5_intr);
+#endif
+}
+#if 0
+static int emac_buffer_full(ppc4xx_emac_t *s)
+{
+#if 0
+ int avail, index, boundary;
+
+ index = s->curpag << 8;
+ boundary = s->boundary << 8;
+ if (index < boundary)
+ avail = boundary - index;
+ else
+ avail = (s->stop - s->start) - (index - boundary);
+ if (avail < (MAX_ETH_FRAME_SIZE + 4))
+ return 1;
+#endif
+ return 0;
+}
+
+static int emac_can_receive(void *opaque)
+{
+#if 0
+ NE2000State *s = opaque;
+
+ if (s->cmd & E8390_STOP)
+ return 1;
+ return !ne2000_buffer_full(s);
+#endif
+ return 0;
+}
+#endif
+
+
+static void emac_receive(void *opaque, const uint8_t *buf, int size)
+{
+ ppc4xx_emac_t* emac = (ppc4xx_emac_t*) opaque;
+
+ DPRINT("%d bytes\n", size);
+ if (emac->reg.RXEN) {
+ if (emac->rx->buf) {
+ if (size<1520) {
+ if (emac->rx[emac->rxPos].mal.bit0_empty) {
+ /* data is allocated with the maximum possible length, on eth =
1520Bytes
+ * len field represent packet size.*/
+ /* We !use Continuos mode, first & last field ignored */
+ unsigned char* dstG = (unsigned char*) ntohl((unsigned long
int)emac->rx[emac->rxPos].buf);
+ unsigned char* dstH= dstG+(unsigned int)phys_ram_base;
+ unsigned short size16 = size;
+ DPRINT(" Delivery message HOST %p-> GUEST %p,pos%d\n",
dstH, dstG, emac->rxPos);
+ EmacMalRxDes_dump(&emac->rx[emac->rxPos]);
+ emac->reg.ocrx += size16;
+ memcpy(dstH, buf, size);
+ emac->rx[emac->rxPos].len = ntohs(size16);
+ emac->rx[emac->rxPos].mal.bit0_empty = 0;
+ if (emac->rx[emac->rxPos].mal.bit5_intr) {
+ /* TODO: use appropriate channel */
+ *rxeobisr = 0xC0000000;
+ qemu_irq_raise(emac->mal_irqs_rxeob);
+ }
+
+ emac->rxPos += (emac->rx[emac->rxPos].mal.bit1_wrap)?
-(emac->rxPos) : 1;
+ } else {
+ if (++emac->rxLostNum == emac->rxLostLimit) {
+ printf(" %d Message lost, board seem hung up!\n",
emac->rxLostNum);
+ emac->rxLostLimit*=10;
+ }
+ }
+ } else {
+ printf(" Message size > 1520, discarding packet\n");
+ }
+ } else {
+ }
+ } else {
+ static int sndOrMore=0;
+ if (!sndOrMore) {
+ printf("emac/mal: Driver !command start yet\n");
+ sndOrMore=1;
+ }
+ }
+#if 0
+#define MIN_BUF_SIZE 60
+ NE2000State *s = opaque;
+ uint8_t *p;
+ unsigned int total_len, next, avail, len, index, mcast_idx;
+ uint8_t buf1[60];
+ static const uint8_t broadcast_macaddr[6] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+#if defined(DEBUG_NE2000)
+ printf("NE2000: received len=%d\n", size);
+#endif
+
+ if (s->cmd & E8390_STOP || ne2000_bufstruct mal_emac_bdfer_full(s))
+ return;
+
+ /* XXX: check this */
+ if (s->rxcr & 0x10) {
+ /* promiscuous: receive all */
+ } else {
+ if (!memcmp(buf, broadcast_macaddr, 6)) {
+ /* broadcast address */
+ if (!(s->rxcr & 0x04))
+ return;
+ } else if (buf[0] & 0x01) {
+ /* multicast */
+ if (!(s->rxcr & 0x08))
+ return;
+ mcast_idx = compute_mcast_idx(buf);
+ if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
+ return;
+ } else if (s->mem[0] == buf[0] &&
+ s->mem[2] == buf[1] &&
+ s->mem[4] == buf[2] &&
+ s->mem[6] == buf[3] &&
+ s->mem[8] == buf[4] &&
+ s->mem[10] == buf[5]) {
+ /* match */
+ } else {
+ return;
+ }
+ }
+
+
+ /* if too small buffer, then expand it */
+ if (size < MIN_BUF_SIZE) {
+ memcpy(buf1, buf, size);
+ memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+ buf = buf1;
+ size = MIN_BUF_SIZE;
+ }
+
+ index = s->curpag << 8;
+ /* 4 bytes for header */
+ total_len = size + 4;
+ /* address for next packet (4 bytes for CRC) */
+ next = index + ((total_len + 4 + 255) & ~0xff);
+ if (next >= s->stop)
+ next -= (s->stop - s->start);
+ /* prepare packet header */
+ p = s->mem + index;
+ s->rsr = ENRSR_RXOK; /* receive status */
+ /* XXX: check this */
+ if (buf[0] & 0x01)
+ s->rsr |= ENRSR_PHY;
+ p[0] = s->rsr;
+ p[1] = next >> 8;
+ p[2] = total_len;
+ p[3] = total_len >> 8;
+ index += 4;
+
+ /* write packet data */
+ while (size > 0) {
+ if (index <= s->stop)
+ avail = s->stop - index;
+ else
+ avail = 0;
+ len = size;
+ if (len > avail)
+ len = avail;
+ memcpy(s->mem + index, buf, len);
+ buf += len;
+ index += len;
+ if (index == s->stop)
+ index = s->start;
+ size -= len;
+ }
+ s->curpag = next >> 8;
+
+ /* now we can signal we have received something */
+ s->isr |= ENISR_RX;
+ ne2000_update_irq(s);
+#endif
+}
+
+void emac_ppc405_init(ppc4xx_emac_t* emac, NICInfo *nd)
+{
+ memcpy(&emac->nic, nd, sizeof(NICInfo));
+ /* We are only be able to receive. Sending packet mean receiver action get
up */
+ emac->vc = qemu_new_vlan_client(nd->vlan, emac_receive,
+ NULL/*emac_can_receive*/, emac);
+
+ snprintf(emac->vc->info_str, sizeof(emac->vc->info_str),
+ "emac macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+ emac->nic.macaddr[0],
+ emac->nic.macaddr[1],
+ emac->nic.macaddr[2],
+ emac->nic.macaddr[3],
+ emac->nic.macaddr[4],
+ emac->nic.macaddr[5]);
+ printf("%s\n", emac->vc->info_str);
+}
+
+static void ppc4xx_emac_reset (void *opaque)
+{
+ ppc4xx_emac_t *emac;
+
+ emac = opaque;
+ emac->rx = NULL;
+ emac->tx = NULL;
+ emac->txPos = emac->rxPos = 0;
+ emac->txNum = emac->rxNum = 0;
+ emac->rxLostNum=0;
+ emac->rxLostLimit=1;
+
+ memset(&emac->reg, 0, sizeof(emac->reg));
+ emac->reg.mr0 = 0xC0000000;
+ emac->reg.tmr1 = 0x380F0000;
+ emac->reg.vtpid = 0x00008808;
+ emac->reg.ptr = 0x0000FFFF;
+ emac->reg.ipgvr = 0x00000004;
+ emac->reg.stacr = 0x00008000;
+ emac->reg.rwmr = 0x04001000;
+
+ /* Now ready to issue mii control transfer */
+ emac->reg.stacr = 0;
+}
+/* It looks like a lot of Linux programs assume page size
+ * is 4kB long. This is evil, but we have to deal with it...
+ *
+#define TARGET_PAGE_BITS 12
+ * Here we have many register.
+ * Do action only for reset or transmit command.
+ * Other will be simple configuration latched during device emulation
+ * es stop rx, allow pause packet.
+ *
+ * Another tip:
+ * When possible only implemente the read of value, since using var read/write
is target indep
+ */
+static uint32_t emac_readl (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t value;
+ ppc4xx_emac_t* emac = (ppc4xx_emac_t*)opaque;
+ uint32_t ind = (addr-emac->base)>>2;
+ /* Keep in a separate way, as stackable code */
+ if (ind>=28) {
+ printf("emac: Out of range register %d!\n", ind);
+ return 0;
+ }
+ value = ((uint32_t*)&emac->reg)[ind];
+ DPRINT("emac: [%d] => %x\n", ind, value);
+ return value/*STACR_OC*/;
+}
+
+static void emac_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ ppc4xx_emac_t* emac = (ppc4xx_emac_t*)opaque;
+ uint32_t ind = (addr-emac->base)>>2;
+
+/* printf("%s: " PADDRX " val %x\n",__func__, addr, value);*/
+ /* Exist some common code for this? */
+ if (ind>=28) {
+ printf("emac: Out of range register %d!\n", ind);
+ return;
+ }
+ switch (ind) {
+ case 20:
+ case 21:
+ case 26:
+ case 27:
+ printf("emac: Attemping to write to read only reg!");
+ return;
+ }
+ DPRINT("emac: [%d] <= %x\n", ind, value);
+ /* Keep in a separate way, as stackable code */
+ ((uint32_t*)&emac->reg)[ind] = value;
+ if (ind==0) {
+ emac->_reg.mr0 = value;
+ /* soft reset */
+ if (emac->_reg.RSTA) {
+ printf("emac: soft reset commanded!\n");
+ ppc4xx_emac_reset(emac);/* Should be protected with a
semaphore, also in emac_receive()? */
+ value &= ~(emac->_reg.RSTA); /* Sw look for this bit
go down */
+ }
+
+ DPRINT("emac: St%s tx channel!\n",
emac->_reg.TXEN?"arting":"opping");
+ DPRINT("emac: St%s rx channel!\n",
emac->_reg.RXEN?"arting":"opping");
+
+ /* Suppose the mal reg was updated, seem a good approximation */
+ if (emac->_reg.TXEN && emac->tx==NULL) {
+ int l=0;
+ emac->tx = (struct EmacMalTxDes*) (txctpr[0] +
phys_ram_base);
+ do { EmacMalTxDes_dump(&emac->tx[l]); } while
(!emac->tx[l].mal.bit1_wrap && l++<50);
+ }
+ if (emac->_reg.RXEN && emac->rx==NULL) {
+ int l=0;
+ emac->rx = (struct EmacMalRxDes*) (rxctpr[0] +
phys_ram_base);
+ do { EmacMalRxDes_dump(&emac->rx[l]); } while
(!emac->rx[l].mal.bit1_wrap && l++<50);
+ }
+ /* A timer that periodically check packet to send
+ emac->tx_timer = qemu_new_timer();*/
+ }
+ if (ind==2) {
+ if (value & 0xC0000000) { /* both channel */
+ if (emac->reg.TXEN) {
+ if (emac->tx[emac->txPos].mal.bit0_ready) {
+ unsigned char* dstG = (unsigned char*)
ntohl((unsigned long int)emac->tx[emac->txPos].buf);
+ unsigned char* dstH= dstG+(unsigned
int)phys_ram_base;
+ unsigned short size16 =
ntohs(emac->tx[emac->txPos].len);
+
+ DPRINT("Sending packet on pos %d\n",
emac->txPos);
+ qemu_send_packet(emac->vc, dstH, size16);
+ emac->reg.octx += size16;
+ if (emac->tx[emac->txPos].mal.bit5_intr) {
+ /* TODO: use appropriate channel */
+ *txeobisr = 0xC0000000;
+ qemu_irq_raise(emac->mal_irqs_txeob);
+ }
+
+ /* Clear status */
+ emac->tx[emac->txPos].mal.bit0_ready = 0;
+ /* 0x808 is stucked at STACR_OC */
+ emac->txPos +=
(emac->tx[emac->txPos].mal.bit1_wrap)? -(emac->txPos) : 1;
+
+ /*
+ * u-boot driver (no os=>no task) poll this bit
until became 0,
+ * but in PPC405GPr User manual nothing said
about this
+ */
+ value &= ~0xC0000000;
+ } else {printf("Processor goes crazy(ready bit was
0)!!! Stopping tx\n");}
+ } else {DPRINT("Tx is disabled\n");}
+ }
+ }
+ if (ind==23) {
+ /* PPC405GPr_UM2004 say, on page 568:
+ * 'EMAC sets EMAC0_STACR[OC] = 0 when the EMAC0_STACR is
written to.'
+ * 'EMAC then sets EMAC0_STACR[OC] = 1 to indicate that the
data has been written to the PHY, or the data'
+ * 'read from the PHY is valid. The device driver should poll
for EMAC0_STACR[OC] = 1 before issuing a new'
+ * 'command, or before using data read from the PHY'
+ *
+ * our approximation:
+ * - initial condition 0
+ * - write(sw start some MII command) 1 (we end in the same
cycle)
+ * - read(poll status) 1
+ * - write(sw start new cmd | ...) 0
+ *
+ * reg write clear (bit index is opposite then those reported
by official manual)
+ * PHYD bit 31:16 Data (RW)
+ * OC bit 15 0 when this reg is addressed, 1 data
written to PHY/data readed correctly from PHY
+ * PHYE bit 14 1 PhyError during read
+ * STAC bit 13:12 00 Reserved/01 Read/10 Write/11 Reserved
+ * OPBC bit 11:10 OPB Bus clock freq. signal EMCMDCIk
+ * PCDA bit 9:5 PHY Command destination address
+ * PRA bit 4:0 PHY Register address
+ *
+ value &= ~(1<<15);*/
+ value ^= (1<<15);
+ value &= ~(1<<14);
+ }
+ /* Keep in a separate way, as stackable code */
+ ((uint32_t*)&emac->reg)[ind] = value;
+}
+static uint32_t emac_readw (void *opaque, target_phys_addr_t addr)
+{
+ printf("Lettura a granularita' word su EMAC " PADDRX "\n",addr);
+ return 0;
+}
+
+static void emac_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ printf("Scrittura a granularita' word su EMAC " PADDRX "\n",addr);
+}
+
+static uint32_t emac_readb (void *opaque, target_phys_addr_t addr)
+{
+ printf("Lettura a granularita' byte su EMAC " PADDRX "\n",addr);
+ return 0;
+}
+
+static void emac_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ printf("Scrittura a granularita' byte su EMAC " PADDRX "\n",addr);
+}
+
+
+static CPUReadMemoryFunc *emac_read[] = {
+ &emac_readb,
+ &emac_readw,
+ &emac_readl,
+};
+
+static CPUWriteMemoryFunc *emac_write[] = {
+ &emac_writeb,
+ &emac_writew,
+ &emac_writel,
+};
+void ppc4xx_emac_init (CPUState *env, ppc4xx_mmio_t *mmio, target_phys_addr_t
offset, NICInfo *nic, qemu_irq mal_irqs[4])
+{
+ ppc4xx_emac_t *emac;
+
+ emac = qemu_mallocz(sizeof(ppc4xx_emac_t));
+ if (emac != NULL) {
+ emac->base = offset;
+#ifdef DEBUG_OPBA
+ printf("%s: offset " PADDRX "\n", __func__, offset);
+#endif
+ ppc4xx_mmio_register(env, mmio, offset, 0x70,
+ emac_read, emac_write, emac);
+ qemu_register_reset(ppc4xx_emac_reset, emac);
+
+ /* One time configuration, HOST related */
+ emac_ppc405_init(emac, nic);
+
+ emac->mal_irqs_txeob = mal_irqs[0];
+ emac->mal_irqs_rxeob = mal_irqs[1];
+ emac->mal_irqs_txerr = mal_irqs[2];
+ emac->mal_irqs_rxerr = mal_irqs[3];
+
+ /* N Time configuration, GUEST related */
+ ppc4xx_emac_reset(emac);
+ }
+}
Index: hw/pflash_cfi02.c
===================================================================
--- hw/pflash_cfi02.c (revision 5720)
+++ hw/pflash_cfi02.c (working copy)
@@ -2,6 +2,7 @@
* CFI parallel flash with AMD command set emulation
*
* Copyright (c) 2005 Jocelyn Mayer
+ * Copyright (c) 2008 Lionetti Salvatore
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,7 +23,7 @@
* For now, this code can emulate flashes of 1, 2 or 4 bytes width.
* Supported commands/modes are:
* - flash read
- * - flash write
+ * - flash write (also buffer mode)
* - flash ID read
* - sector erase
* - chip erase
@@ -34,14 +35,20 @@
* It does not implement software data protection as found in many real chips
* It does not implement erase suspend/resume commands
* It does not implement multiple sectors erase
+ *
+ * Revisione done to optimize, (the next'll be mmap()), expecially for
WriteBufferLoad command.
+ * Use different name for structure, so multiple device could be
address@hidden time
*/
#include "hw.h"
#include "flash.h"
#include "qemu-timer.h"
#include "block.h"
+#include "cpu-all.h" /* To have FLASH_LOG_CFI */
+#include "exec-all.h" /* To have loglevel */
-//#define PFLASH_DEBUG
+#define USE_SIMPLE_TABLE
+/*#define PFLASH_DEBUG*/
#ifdef PFLASH_DEBUG
#define DPRINTF(fmt, args...) \
do { \
@@ -51,7 +58,8 @@
#define DPRINTF(fmt, args...) do { } while (0)
#endif
-struct pflash_t {
+#define pflash_cfi02_t pflash_t
+struct pflash_cfi02_t {
BlockDriverState *bs;
target_phys_addr_t base;
uint32_t sector_len;
@@ -60,18 +68,30 @@
int width;
int wcycle; /* if 0, the flash is read normally */
int bypass;
+ uint32_t bytes2write; /* In buffer load mode, must remember the number of
bytes to elaborate */
+ uint8_t buffer_loading; /* For buffer load mode 1 mean read nword-1 &
apply write & apply end command */
+ uint32_t buffer_loading_start;
+ uint32_t buffer_loading_end;
int ro;
uint8_t cmd;
uint8_t status;
uint16_t ident[4];
uint16_t unlock_addr[2];
uint8_t cfi_len;
- uint8_t cfi_table[0x52];
+ uint8_t cfi_table[0x80];
QEMUTimer *timer;
ram_addr_t off;
int fl_mem;
int rom_mode;
void *storage;
+#if 0
+ /* Layer needed to optimize (driver common size) Vs (device common size)
+ * Used by timer() & update(), update() use SIGNED!!!
+ * A simple way to represent a list of number. */
+ int pendingW;
+ int fstSector;
+ int curSector;
+#endif
};
static void pflash_register_memory(pflash_t *pfl, int rom_mode)
@@ -88,9 +108,41 @@
pfl->chip_len, phys_offset);
}
+static void pflash_cfi02_core_reset (void *opaque) {
+ struct pflash_cfi02_t *pfl = (struct pflash_cfi02_t*)opaque;
+
+ pfl->bypass = 0;
+ pfl->wcycle = 0;
+ pfl->cmd = 0;
+ pfl->status = 0;
+
+ pfl->bytes2write = 0;
+ pfl->buffer_loading = 0;
+ pfl->buffer_loading_start = 0;
+ pfl->buffer_loading_end = 0;
+
+/* pfl->pendingW = pfl->fstSector = curSector = 0; Lost current write? */
+
+ pflash_register_memory(pfl, 1);
+}
+
+static void pflash_cfi02_reset (void *opaque) {
+ struct pflash_cfi02_t *pfl = (struct pflash_cfi02_t*)opaque;
+
+ qemu_del_timer(pfl->timer);
+#if 0 /* XXX: there should be a bit to set up read-only,
+ * the same way the hardware does (with WP pin).
+ */
+ pfl->ro = 1;
+#else
+ pfl->ro = 0;
+#endif
+ pflash_cfi02_core_reset(pfl);
+ printf("Resetting cfi chip!\n");
+}
static void pflash_timer (void *opaque)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
/* Reset flash */
@@ -104,13 +156,12 @@
pfl->cmd = 0;
}
-static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width)
+static uint32_t pflash_read (struct pflash_cfi02_t *pfl, uint32_t offset, int
width)
{
- uint32_t boff;
+ uint32_t boff, _boff;
uint32_t ret;
uint8_t *p;
- DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset);
ret = -1;
offset -= pfl->base;
if (pfl->rom_mode) {
@@ -119,7 +170,7 @@
pflash_register_memory(pfl, 1);
}
offset &= pfl->chip_len - 1;
- boff = offset & 0xFF;
+ boff = _boff = offset & 0xFF;
if (pfl->width == 2)
boff = boff >> 1;
else if (pfl->width == 4)
@@ -136,32 +187,34 @@
flash_read:
/* Flash area read */
p = pfl->storage;
+ p += offset;
+common_read:
switch (width) {
case 1:
- ret = p[offset];
+ ret = p[0];
// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
break;
case 2:
#if defined(TARGET_WORDS_BIGENDIAN)
- ret = p[offset] << 8;
- ret |= p[offset + 1];
+ ret = p[0] << 8;
+ ret |= p[1];
#else
- ret = p[offset];
- ret |= p[offset + 1] << 8;
+ ret = p[0];
+ ret |= p[1] << 8;
#endif
// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
break;
case 4:
#if defined(TARGET_WORDS_BIGENDIAN)
- ret = p[offset] << 24;
- ret |= p[offset + 1] << 16;
- ret |= p[offset + 2] << 8;
- ret |= p[offset + 3];
+ ret = p[0] << 24;
+ ret |= p[1] << 16;
+ ret |= p[2] << 8;
+ ret |= p[3];
#else
- ret = p[offset];
- ret |= p[offset + 1] << 8;
- ret |= p[offset + 2] << 16;
- ret |= p[offset + 3] << 24;
+ ret = p[0];
+ ret |= p[1] << 8;
+ ret |= p[2] << 16;
+ ret |= p[3] << 24;
#endif
// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
break;
@@ -199,16 +252,81 @@
break;
case 0x98:
/* CFI query mode */
- if (boff > pfl->cfi_len)
+ if (_boff > pfl->cfi_len)
ret = 0;
- else
- ret = pfl->cfi_table[boff];
+ else {
+#ifndef USE_SIMPLE_TABLE
+ ret = pfl->cfi_table[_boff];
+#else
+ p = &pfl->cfi_table[_boff];
+ goto common_read;
+#endif
+ }
break;
}
+ DPRINTF("%s: offset " TARGET_FMT_lx " value 0x%x width %d func %x\n",
__func__, _boff, ret, width, pfl->cmd);
return ret;
}
+#if 0
+/*
+ * update flash content on disk
+ * Act as intermediate between
+ * - 32B from Driver
+ * - 512B of device
+ * Optimize only when length==32 & Write only when sector is crossed
+ * Need a timer that commit if no more write? No if we write every 512B
+ * RAM is always updated
+ */
+#define PFLASH_512BLOCK 8 /* 0 -> sector of 512B, 1 -> sector of 1024B,
... */
+#define PFLASH_XBLOCK (9 + PFLASH_512BLOCK)
+#define PFLASH_XBOUND ((1 << PFLASH_XBLOCK)-1)
+static inline void pflash_update(struct pflash_cfi02_t *pfl, int offset,
+ int size)
+{
+ int offset_end;
+ int grouped = 0; /* Current version is linked with internal cache */
+ int forcefl = 0; /* Force flush after all op */
+
+ if (pfl->bs) {
+ int _offset = offset;
+ offset = offset >> PFLASH_XBLOCK;
+
+ /* Try to group sequential write
+ * Stop also if found a sector bound! (so avoid timer for now)
*/
+ if (size == 32) {
+ forcefl = (((_offset+size)&PFLASH_XBOUND/*511*/)==0);
+ if (pfl->pendingW) {
+ /* Try to group with previous write() */
+ grouped = (offset == pfl->curSector);
+ } else {
+ /* First write in this group */
+ pfl->fstSector = offset;
+ pfl->curSector = offset;
+ pfl->pendingW = 1;
+ grouped = 1;
+ }
+ }
+
+ /* Commit any pending write if the case. */
+ if ((pfl->pendingW && !grouped) || forcefl) {
+ DPRINTF("%s: flushing sectors " TARGET_FMT_lx " ns
%d\n", __func__, pfl->fstSector, pfl->curSector - pfl->fstSector + 1);
+ bdrv_write(pfl->bs, pfl->fstSector<<PFLASH_512BLOCK,
pfl->storage + (pfl->fstSector << (PFLASH_XBLOCK)), (pfl->curSector -
pfl->fstSector + 1)<<(PFLASH_512BLOCK));
+ pfl->pendingW = 0;
+ }
+
+ /* Current write (!in case we just do it with previous commit)
*/
+ if (!grouped) {
+ offset_end = _offset + size;
+ /* round to sectors */
+ offset_end = (offset_end + 511) >> 9;
+ DPRINTF("%s: flushing sectors " TARGET_FMT_lx " ns
%d\n", __func__, offset, offset_end - offset);
+ bdrv_write(pfl->bs, offset, pfl->storage + (offset <<
9), offset_end - offset);
+ }
+ }
+}
+#endif
/* update flash content on disk */
static void pflash_update(pflash_t *pfl, int offset,
int size)
@@ -224,7 +342,7 @@
}
}
-static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value,
+static void pflash_write (struct pflash_cfi02_t *pfl, uint32_t offset,
uint32_t value,
int width)
{
uint32_t boff;
@@ -232,31 +350,32 @@
uint8_t cmd;
cmd = value;
- if (pfl->cmd != 0xA0 && cmd == 0xF0) {
-#if 0
- DPRINTF("%s: flash reset asked (%02x %02x)\n",
- __func__, pfl->cmd, cmd);
+ if (pfl->cmd != 0xA0 && pfl->cmd != 0x25 && cmd == 0xF0) {
+#if 1
+ DPRINTF("%s: flash reset asked, cmd(%02x) " TARGET_FMT_lx " %x %d\n",
+ __func__, pfl->cmd, (char*)offset-(char*)pfl->storage, value,
width);
#endif
goto reset_flash;
}
- DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__,
- offset, value, width, pfl->wcycle);
+
offset -= pfl->base;
offset &= pfl->chip_len - 1;
- DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__,
- offset, value, width);
boff = offset & (pfl->sector_len - 1);
if (pfl->width == 2)
boff = boff >> 1;
else if (pfl->width == 4)
boff = boff >> 2;
+
+ DPRINTF("%s: offset " TARGET_FMT_lx " val %x wid %d wcycle %d\n", __func__,
+ boff, value, width, pfl->wcycle);
+
switch (pfl->wcycle) {
case 0:
/* Set the device in I/O access mode if required */
if (pfl->rom_mode)
pflash_register_memory(pfl, 0);
- /* We're in read mode */
+ /* We're in read mode */
check_unlock0:
if (boff == 0x55 && cmd == 0x98) {
enter_CFI_mode:
@@ -265,26 +384,40 @@
pfl->cmd = 0x98;
return;
}
- if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
+ if (!(boff == pfl->unlock_addr[0] || boff == 0x5555) || cmd != 0xAA) {
DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n",
__func__, boff, cmd, pfl->unlock_addr[0]);
goto reset_flash;
}
DPRINTF("%s: unlock sequence started\n", __func__);
+ pfl->wcycle++;
break;
case 1:
/* We started an unlock sequence */
check_unlock1:
- if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
+ if (!(boff == pfl->unlock_addr[1] || boff == 0x2AAA) || cmd != 0x55) {
DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__,
boff, cmd);
goto reset_flash;
}
DPRINTF("%s: unlock sequence done\n", __func__);
+ pfl->wcycle++;
break;
case 2:
+ /* Command write buffer load. */
+ if (boff==0 && cmd==0x25) {
+ /* Wait #word - 1 on same addr */
+ DPRINTF("%s: start buffer load, expect len4next write\n",
__func__);
+ pfl->buffer_loading=1;
+ pfl->wcycle--;
+ } else if (pfl->buffer_loading) {
+ pfl->bytes2write=(value+1)<<(width>>1);
+ DPRINTF("%s: got %d bytes2write\n", __func__, pfl->bytes2write);
+ pfl->wcycle++;
+ break;
+ } else
/* We finished an unlock sequence */
- if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
+ if (!pfl->bypass && (boff != pfl->unlock_addr[0] && boff != 0x5555)) {
DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__,
boff, cmd);
goto reset_flash;
@@ -296,19 +429,29 @@
case 0x80:
case 0x90:
case 0xA0:
- pfl->cmd = cmd;
- DPRINTF("%s: starting command %02x\n", __func__, cmd);
- break;
+ case 0x25:
+ pfl->cmd = cmd;
+ DPRINTF("%s: starting command %02x\n", __func__, cmd);
+ break;
default:
DPRINTF("%s: unknown command %02x\n", __func__, cmd);
goto reset_flash;
}
- break;
+ pfl->wcycle++;
+ break;
case 3:
switch (pfl->cmd) {
case 0x80:
/* We need another unlock sequence */
goto check_unlock0;
+ case 0x25:
+ if (pfl->bytes2write==0) {
+ printf("%s: buffer mode have 0 bytes2write!\n", __func__);
+ goto reset_flash;
+ }
+ if (!pfl->buffer_loading_start)
+ pfl->buffer_loading_start=offset;
+ pfl->buffer_loading_end=offset+width;
case 0xA0:
DPRINTF("%s: write data offset " TARGET_FMT_lx " %08x %d\n",
__func__, offset, value, width);
@@ -343,11 +486,24 @@
pflash_update(pfl, offset, 4);
break;
}
- pfl->status = 0x00 | ~(value & 0x80);
- /* Let's pretend write is immediate */
- if (pfl->bypass)
- goto do_bypass;
- goto reset_flash;
+ /* In buffer load mode, status is available only after requested
bytes2write */
+ if (pfl->cmd!=0x25) {
+ pfl->status = 0x00 | ~(value & 0x80);
+ /* Let's pretend write is immediate */
+ if (pfl->bypass)
+ goto do_bypass;
+ goto reset_flash;
+ } else {
+ if (pfl->bytes2write>=width)
+ pfl->bytes2write-=width;
+ else {
+ printf("%s: buffer mode discarded %d bytes at end
of transfer\n",__func__,width-pfl->bytes2write);
+ pfl->bytes2write=0;
+ }
+ if (pfl->bytes2write)
+ pfl->wcycle--; /* Dangerous if use timer */
+ }
+ break;
case 0x90:
if (pfl->bypass && cmd == 0x00) {
/* Unlock bypass reset */
@@ -362,6 +518,8 @@
__func__, pfl->cmd);
goto reset_flash;
}
+ pfl->wcycle++;
+ break;
case 4:
switch (pfl->cmd) {
case 0xA0:
@@ -370,6 +528,13 @@
return;
case 0x80:
goto check_unlock1;
+ case 0x25:
+ DPRINTF("%s: Buffer load terminated %s (%d bytes remaining)\n",
__func__, !pfl->bytes2write?"Ok" : "NOK", pfl->bytes2write);
+ /* Update written sequence
+ pflash_update(pfl, pfl->buffer_loading_start,
pfl->buffer_loading_end - pfl->buffer_loading_start); */
+ pfl->buffer_loading = 0;
+ pfl->buffer_loading_start = 0;
+ goto reset_flash;
default:
/* Should never happen */
DPRINTF("%s: invalid command state %02x (wc 4)\n",
@@ -436,18 +601,15 @@
DPRINTF("%s: invalid write state (wc 7)\n", __func__);
goto reset_flash;
}
- pfl->wcycle++;
-
return;
/* Reset flash */
reset_flash:
- pfl->bypass = 0;
- pfl->wcycle = 0;
- pfl->cmd = 0;
+ pflash_cfi02_core_reset(pfl);
return;
do_bypass:
+ DPRINTF("Requesting bypass\n");
pfl->wcycle = 2;
pfl->cmd = 0;
return;
@@ -461,14 +623,14 @@
static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
return pflash_read(pfl, addr, 2);
}
static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
return pflash_read(pfl, addr, 4);
}
@@ -482,7 +644,7 @@
static void pflash_writew (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
pflash_write(pfl, addr, value, 2);
}
@@ -490,7 +652,7 @@
static void pflash_writel (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
pflash_write(pfl, addr, value, 4);
}
@@ -507,6 +669,7 @@
&pflash_readl,
};
+#ifndef USE_SIMPLE_TABLE
/* Count trailing zeroes of a 32 bits quantity */
static int ctz32 (uint32_t n)
{
@@ -540,15 +703,15 @@
return ret;
}
-
+#endif
pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
BlockDriverState *bs, uint32_t sector_len,
int nb_blocs, int nb_mappings, int width,
uint16_t id0, uint16_t id1,
uint16_t id2, uint16_t id3,
- uint16_t unlock_addr0, uint16_t unlock_addr1)
+ uint16_t unlock_addr0, uint16_t unlock_addr1)
{
- pflash_t *pfl;
+ struct pflash_cfi02_t *pfl;
int32_t chip_len;
chip_len = sector_len * nb_blocs;
@@ -558,9 +721,11 @@
total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
return NULL;
#endif
- pfl = qemu_mallocz(sizeof(pflash_t));
+ pfl = qemu_mallocz(sizeof(struct pflash_cfi02_t));
if (pfl == NULL)
return NULL;
+
+ /* One time initialization, HOST related. */
pfl->storage = phys_ram_base + off;
pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops,
pfl);
@@ -574,7 +739,7 @@
/* read the initial flash content */
bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
}
-#if 0 /* XXX: there should be a bit to set up read-only,
+ #if 0 /* XXX: there should be a bit to set up read-only,
* the same way the hardware does (with WP pin).
*/
pfl->ro = 1;
@@ -593,6 +758,7 @@
pfl->ident[3] = id3;
pfl->unlock_addr[0] = unlock_addr0;
pfl->unlock_addr[1] = unlock_addr1;
+#ifndef USE_SIMPLE_TABLE
/* Hardcoded CFI table (mostly from SG29 Spansion flash) */
pfl->cfi_len = 0x52;
/* Standard "QRY" string */
@@ -621,22 +787,22 @@
pfl->cfi_table[0x1E] = 0x00;
/* Reserved */
pfl->cfi_table[0x1F] = 0x07;
- /* Timeout for min size buffer write (NA) */
- pfl->cfi_table[0x20] = 0x00;
+ /* Timeout for min size buffer write (16 s) */
+ pfl->cfi_table[0x20] = 0x04;
/* Typical timeout for block erase (512 ms) */
pfl->cfi_table[0x21] = 0x09;
/* Typical timeout for full chip erase (4096 ms) */
pfl->cfi_table[0x22] = 0x0C;
/* Reserved */
pfl->cfi_table[0x23] = 0x01;
- /* Max timeout for buffer write (NA) */
- pfl->cfi_table[0x24] = 0x00;
+ /* Max timeout for buffer write */
+ pfl->cfi_table[0x24] = 0x04;
/* Max timeout for block erase */
pfl->cfi_table[0x25] = 0x0A;
/* Max timeout for chip erase */
pfl->cfi_table[0x26] = 0x0D;
/* Device size */
- pfl->cfi_table[0x27] = ctz32(chip_len);
+ pfl->cfi_table[0x27] = ctz32(chip_len) + 1;
/* Flash device interface (8 & 16 bits) */
pfl->cfi_table[0x28] = 0x02;
pfl->cfi_table[0x29] = 0x00;
@@ -652,7 +818,7 @@
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
pfl->cfi_table[0x2F] = sector_len >> 8;
pfl->cfi_table[0x30] = sector_len >> 16;
-
+
/* Extended */
pfl->cfi_table[0x31] = 'P';
pfl->cfi_table[0x32] = 'R';
@@ -660,7 +826,6 @@
pfl->cfi_table[0x34] = '1';
pfl->cfi_table[0x35] = '0';
-
pfl->cfi_table[0x36] = 0x00;
pfl->cfi_table[0x37] = 0x00;
pfl->cfi_table[0x38] = 0x00;
@@ -670,6 +835,31 @@
pfl->cfi_table[0x3b] = 0x00;
pfl->cfi_table[0x3c] = 0x00;
+#else
+ /* Don't know why but driver expect this
+ * Now this table have !to be 'interpolated' basing on width.
+ * Moreover we were called with width == 4. */
+ pfl->cfi_len = 0x80;
+ pfl->cfi_table[0x21] = 'Q';
+ pfl->cfi_table[0x23] = 'R';
+ pfl->cfi_table[0x25] = 'Y';
+ pfl->cfi_table[0x27] = 2; /* oam command set */
+ pfl->cfi_table[0x4F] = 25; /* size = 2^x Bytes*/
+ pfl->cfi_table[0x59] = 1; /* num of blocks */
+ pfl->cfi_table[0x5b] = 255; /* sectors */
+ pfl->cfi_table[0x61] = 2; /* sector size */
+#endif
- return pfl;
+#if 0
+ /* Per reset initialization, GUEST related.
+ *
+ * Reset action is needed, since memory attribute is changed over the
writing process
+ * @reset we address@hidden read from flash.
+ * Actually we stop all started action (reset chip)
+ */
+ pflash_cfi02_reset(pfl);
+ qemu_register_reset(&pflash_cfi02_reset, pfl);
+#endif
+
+ return (pflash_t*)pfl;
}
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,7 +1403,37 @@
}
/*****************************************************************************/
-/* I2C controller */
+/*
+ * 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.
+ */
+#define I2C_VER2
+/* Generic function like:
+ * hw/hw.h
+ * These should really be in isa.h, but are here to make pc.h happy. *
+ typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t
data);
+ typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
+ *
+ * cpu-all.h
+ typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr,
uint32_t value);
+ typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t
addr);
+ *
+ * qemu-common.h
+ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
+ typedef int IOCanRWHandler(void *opaque);
+ typedef void IOHandler(void *opaque);
+
+ typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos,
int size);
+
+ THERE !EXIST SIMPLE int read(int fd, const char* pos, int len), CREATE IT
+ */
+KRHandler* readF=NULL;
+KRHandler* writeF=NULL;
+
typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
struct ppc4xx_i2c_t {
target_phys_addr_t base;
@@ -1415,21 +1453,82 @@
uint8_t xfrcnt;
uint8_t xtcntlss;
uint8_t directcntl;
+
+ /* This is treated like a FIFO with same OPB beat (!implemented) */
+ uint8_t dataLen;
+ uint8_t data[4]; /* This is on PPC405GPr, uP dependent */
+ void* opaque;
};
+/*
+ * This method simulate the insertion of a byte on 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;
+#if 0
#ifdef DEBUG_I2C
printf("%s: addr " PADDRX "\n", __func__, addr);
#endif
+#endif
i2c = opaque;
switch (addr - i2c->base) {
case 0x00:
+#ifndef I2C_VER2
// i2c_readbyte(&i2c->mdata);
ret = i2c->mdata;
+#else
+#ifdef DEBUG_I2C
+ printf("I2C read %x (hnd %p)\n", i2c->mdata, readF);
+#endif
+ ret = ppc4xx_i2c_popb(i2c);
+#endif
break;
case 0x02:
ret = i2c->sdata;
@@ -1477,9 +1576,11 @@
ret = 0x00;
break;
}
+#if 0
#ifdef DEBUG_I2C
printf("%s: addr " PADDRX " %02" PRIx32 "\n", __func__, addr, ret);
#endif
+#endif
return ret;
}
@@ -1489,14 +1590,20 @@
{
ppc4xx_i2c_t *i2c;
+#if 0
#ifdef DEBUG_I2C
printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value);
#endif
+#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;
@@ -1509,6 +1616,62 @@
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));
+ if (lettu && readF) {
+ ret = readF(addr, i2c->data, len);
+ }
+ if (!lettu && writeF) {
+ ret = writeF(addr, i2c->data, len);
+ }
+#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;
@@ -1967,6 +2130,15 @@
uint32_t rcbs[2];
};
+/* TODO: need interaction between device!
+ * very difficult since all struct is in .c file */
+uint32_t txctpr[4];
+uint32_t rxctpr[2];
+uint32_t rcbs[2];
+uint32_t *rxeobisr;
+uint32_t *txeobisr;
+uint32_t *rxcasr;
+
static void ppc40x_mal_reset (void *opaque);
static target_ulong dcr_read_mal (void *opaque, int dcrn)
@@ -2067,21 +2239,29 @@
mal->txcarr = val & 0xF0000000;
break;
case MAL0_TXEOBISR:
- /* Read/clear */
- mal->txeobisr &= ~val;
+ /* Read/clear TODO SEPARATE CHANNEL */
+ if (mal->txeobisr & val & 0xC0000000) {
+ mal->txeobisr &= ~val;
+ qemu_irq_lower(mal->irqs[0]);
+ }
+ mal->txeobisr &= ~val;
break;
case MAL0_TXDEIR:
/* Read/clear */
mal->txdeir &= ~val;
break;
case MAL0_RXCASR:
- mal->rxcasr = val & 0xC0000000;
+ 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->irqs[1]);
+ }
mal->rxeobisr &= ~val;
break;
case MAL0_RXDEIR:
@@ -2101,6 +2281,7 @@
idx = 3;
update_tx_ptr:
mal->txctpr[idx] = val;
+ txctpr[idx] = val;
break;
case MAL0_RXCTP0R:
idx = 0;
@@ -2109,6 +2290,7 @@
idx = 1;
update_rx_ptr:
mal->rxctpr[idx] = val;
+ rxctpr[idx] = val;
break;
case MAL0_RCBS0:
idx = 0;
@@ -2117,6 +2299,7 @@
idx = 1;
update_rx_size:
mal->rcbs[idx] = val & 0x000000FF;
+ rcbs[idx] = val & 0x000000FF;
break;
}
}
@@ -2135,6 +2318,10 @@
mal->txcasr = 0x00000000;
mal->txdeir = 0x00000000;
mal->txeobisr = 0x00000000;
+
+ rxeobisr = &(mal->rxeobisr);
+ txeobisr = &(mal->txeobisr);
+ rxcasr = &(mal->rxcasr);
}
void ppc405_mal_init (CPUState *env, qemu_irq irqs[4])
@@ -2234,6 +2421,7 @@
qemu_system_reset_request();
}
+/* ->halted=1 seem that loose memory. */
void store_40x_dbcr0 (CPUState *env, uint32_t val)
{
switch ((val >> 28) & 0x3) {
@@ -2891,7 +3079,8 @@
}
}
-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)
@@ -2906,7 +3095,9 @@
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;
@@ -2970,7 +3161,11 @@
mal_irqs[2] = pic[13];
mal_irqs[3] = pic[14];
ppc405_mal_init(env, mal_irqs);
- /* Ethernet */
+ /* EMAC (Ethernet Media Access Controller) */
+ {
+ void ppc4xx_emac_init(CPUState *env, ppc4xx_mmio_t *mmio,
target_phys_addr_t offset, NICInfo* nic, qemu_irq irq[4]);
+ ppc4xx_emac_init(env, mmio, 0x800, &nd_table[0], mal_irqs);
+ }
/* Uses pic[9], pic[15], pic[17] */
/* CPU control */
ppc405ep_cpc_init(env, clk_setup, sysclk);
Index: hw/ppc4xx_devs.c
===================================================================
--- hw/ppc4xx_devs.c (revision 5720)
+++ hw/ppc4xx_devs.c (working copy)
@@ -26,6 +26,7 @@
#include "ppc4xx.h"
#include "sysemu.h"
#include "qemu-log.h"
+#include "qemu-timer.h"
//#define DEBUG_MMIO
//#define DEBUG_UNASSIGNED
@@ -296,10 +297,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 +367,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
Index: hw/ppc405.h
===================================================================
--- hw/ppc405.h (revision 5720)
+++ hw/ppc405.h (working copy)
@@ -97,7 +97,8 @@
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],
+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);
Index: hw/boards.h
===================================================================
--- hw/boards.h (revision 5720)
+++ hw/boards.h (working copy)
@@ -38,6 +38,7 @@
extern QEMUMachine heathrow_machine;
extern QEMUMachine ref405ep_machine;
extern QEMUMachine taihu_machine;
+extern QEMUMachine walnut_machine;
/* mips_r4k.c */
extern QEMUMachine mips_machine;
Index: pc-bios/u-boot.bin
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: pc-bios/u-boot.bin
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Unisciti alla community di Io fotografo e video, il nuovo corso di
fotografia di Gazzetta dello sport:
http://www.flickr.com/groups/iofotografoevideo
u-boot.bin.gz
Description: GNU Zip compressed data