diff -NurpP --minimal -x '*softmmu' -x '*user' qemu-0.9.0/hw/cafe_pci.c qemu-0.9.0-olpc_v01/hw/cafe_pci.c --- qemu-0.9.0/hw/cafe_pci.c 1969-12-31 19:00:00.000000000 -0500 +++ qemu-0.9.0-olpc_v01/hw/cafe_pci.c 2007-02-12 01:22:00.000000000 -0500 @@ -0,0 +1,838 @@ +/* + * Marvell 88ALP01 Cafe Controller + * + * Copyright (c) 2007 Herbert Poetzl + * + * This code is licenced under the GPL v2.0 + * + */ + +#include "vl.h" +// #include + +#if 0 +#define cafe_log(fmt, ...) printf("cafe: " fmt "\n", ##__VA_ARGS__) +#else +#define cafe_log(fmt, ...) do { } while (0) +#endif + +#if 0 +#define nand_log(fmt, ...) printf("nand: " fmt "\n", ##__VA_ARGS__) +#else +#define nand_log(fmt, ...) do { } while (0) +#endif + + +/* Common declarations for all PCI devices. */ + +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_STATUS 0x06 /* 16 bits */ + +#define PCI_REVISION_ID 0x08 /* 8 bits */ +#define PCI_SUBSUB_CODE 0x09 /* 8 bits */ +#define PCI_SUBCLASS_CODE 0x0a /* 8 bits */ +#define PCI_CLASS_CODE 0x0b /* 8 bits */ + +#define PCI_CACHELINE_SIZE 0x0c /* 8 bits */ +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ +#define PCI_BIST 0x0f /* 8 bits */ + +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ +#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */ +#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits */ +#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ +#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ +#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ + +#define PCI_CARDBUS_CIS 0x28 /* 32 bits */ +#define PCI_SUBS_VENDOR_ID 0x2c /* 16 bits */ +#define PCI_SUBSYSTEM_ID 0x2e /* 16 bits */ +#define PCI_EXPANSION_ROM 0x30 /* 32 bits */ + +#define PCI_COMPATIBILITY 0x34 /* 8 bits */ + +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ +#define PCI_MIN_GRANT 0x3e /* 8 bits */ +#define PCI_MAX_LATENCY 0x3f /* 8 bits */ + + +#define PCI_HEADER_TYPE_NORMAL 0 +#define PCI_HEADER_TYPE_BRIDGE 1 +#define PCI_HEADER_TYPE_CARDBUS 2 + + +#define PCI_CONFIG_8(offset, value) \ + (pci_conf[offset] = (value)) +#define PCI_CONFIG_16(offset, value) \ + (*(uint16_t *)&pci_conf[offset] = cpu_to_le16(value)) +#define PCI_CONFIG_32(offset, value) \ + (*(uint32_t *)&pci_conf[offset] = cpu_to_le32(value)) + +#define PCI_CONFIG_CLASS(value) do { \ + PCI_CONFIG_8(PCI_SUBSUB_CODE, (value & 0xff)); \ + PCI_CONFIG_8(PCI_SUBCLASS_CODE, ((value >> 8) & 0xff)); \ + PCI_CONFIG_8(PCI_CLASS_CODE, ((value >> 16) & 0xff)); \ + } while (0); + + + +/* Marvell 88ALP01 Cafe Registers */ + + +#define CAFE_NAND_CTRL1 0x00 +#define CAFE_NAND_CTRL2 0x04 +#define CAFE_NAND_CTRL3 0x08 +#define CAFE_NAND_STATUS 0x0c +#define CAFE_NAND_IRQ 0x10 +#define CAFE_NAND_IRQ_MASK 0x14 +#define CAFE_NAND_DATA_LEN 0x18 +#define CAFE_NAND_ADDR1 0x1c +#define CAFE_NAND_ADDR2 0x20 +#define CAFE_NAND_TIMING1 0x24 +#define CAFE_NAND_TIMING2 0x28 +#define CAFE_NAND_TIMING3 0x2c +#define CAFE_NAND_NONMEM 0x30 +#define CAFE_NAND_ECC_CODE 0x34 +#define CAFE_NAND_ECC_READ 0x38 +#define CAFE_NAND_ECC_RESULT 0x3C +#define CAFE_NAND_DMA_CTRL 0x40 +#define CAFE_NAND_DMA_ADDR0 0x44 +#define CAFE_NAND_DMA_ADDR1 0x48 +#define CAFE_NAND_ECC_SYN01 0x50 +#define CAFE_NAND_ECC_SYN23 0x54 +#define CAFE_NAND_ECC_SYN45 0x58 +#define CAFE_NAND_ECC_SYN67 0x5c +#define CAFE_NAND_READ_DATA 0x1000 +#define CAFE_NAND_WRITE_DATA 0x2000 + +#define CAFE_GLOBAL_CTRL 0x3004 +#define CAFE_GLOBAL_IRQ 0x3008 +#define CAFE_GLOBAL_IRQ_MASK 0x300c +#define CAFE_NAND_RESET 0x3034 + + +/* Marvell 88ALP01 PCI */ + +#define PCI_MEM_MASK 0x3fff +#define PCI_MEM_SIZE 0x4000 +#define PCI_IO_SIZE 0x1000 + +#define PCI_CLASS_FLASH 0x050100 +#define PCI_VENDOR_MARVELL 0x11ab +#define PCI_DEVICE_CAFE 0x4100 + +#define PCI_COMMAND_IOACCESS 0x0001 +#define PCI_COMMAND_MEMACCESS 0x0002 +#define PCI_COMMAND_BUSMASTER 0x0004 + +/* I/O sizes */ + +#define CAFE_PIO_READ_SIZE 0x1000 +#define CAFE_PIO_WRITE_SIZE 0x1000 +#define CAFE_DMA_BUF_SIZE 0x1000 + +#define CAFE_PAGE_BUF_SIZE 0x0A00 +#define CAFE_PAGE_SIZE 0x0840 + + +typedef struct { + BlockDriverState *bds; + + uint32_t status; +} NANDState; + +typedef struct { + PCIDevice dev; + NANDState nand[MAX_NAND]; + + uint32_t mmio; + + /* control and status */ + uint32_t ctrl; + uint32_t ctrl2; + uint32_t ctrl3; + uint32_t status; + + /* data len and address */ + uint32_t data_len; + uint32_t col_addr; + uint32_t row_addr; + + /* interrupt */ + uint32_t irq; + uint32_t irq_mask; + uint32_t global_irq_mask; + + /* dma */ + uint32_t dma_ctrl; + uint32_t dma_addr0; + uint32_t dma_addr1; + + /* ecc stuff */ + uint32_t ecc_code; + uint32_t ecc_read; + uint32_t ecc_result; + uint32_t syndrome[4]; + + uint8_t *pio_read; + uint8_t *pio_write; + + uint8_t *dma_buf; + uint8_t *page_buf; + + + +} CAFEState; + + + + +static void cafe_update_irq(CAFEState *s) +{ + int level = 0; + + pci_set_irq(&s->dev, 3, level); +} + +static void cafe_reset(CAFEState *s) +{ + cafe_log("reset"); + + s->ctrl = 0; + s->ctrl2 = 0; + s->ctrl3 = 0; + s->status = (1 << 30); + + s->data_len = 0; + s->col_addr = 0; + s->row_addr = 0; + + /* interrupt */ + s->irq = 0; + s->irq_mask = 0; + s->global_irq_mask = 0; + cafe_update_irq(s); + + /* dma */ + s->dma_ctrl = 0; + s->dma_addr0 = 0; + s->dma_addr1 = 0; + +} + +static void cafe_pci_reset(CAFEState *s) +{ + uint8_t *pci_conf = s->dev.config; + + PCI_CONFIG_CLASS(PCI_CLASS_FLASH); + PCI_CONFIG_16(PCI_VENDOR_ID, PCI_VENDOR_MARVELL); + PCI_CONFIG_16(PCI_DEVICE_ID, PCI_DEVICE_CAFE); + PCI_CONFIG_8(PCI_REVISION_ID, 10); + PCI_CONFIG_16(PCI_COMMAND, 0x0000); + PCI_CONFIG_16(PCI_STATUS, 0x2800); + PCI_CONFIG_8(PCI_LATENCY_TIMER, 32); + PCI_CONFIG_8(PCI_HEADER_TYPE, PCI_HEADER_TYPE_NORMAL); + PCI_CONFIG_8(PCI_INTERRUPT_PIN, 1); +} + + +typedef struct { + uint32_t ecc_code; + uint32_t ecc_read; + uint32_t ecc_result; + uint32_t syndrome[4]; + + uint32_t page_reads; + uint32_t page_writes; + uint32_t page_erases; + + uint32_t flags; +} PAGEInfo; + + +static inline PAGEInfo *page_info(uint8_t *page) +{ + return (PAGEInfo *) + (page + CAFE_PAGE_BUF_SIZE - sizeof(PAGEInfo)); +} + +#define PAGE_INITIALIZED 0x0001 +#define PAGE_CLEAN 0x0010 +#define PAGE_PROGRAMMED 0x0020 + +static void nand_init_page(uint8_t *page) +{ + PAGEInfo *info = page_info(page); + + /* erase OOB data */ + memset(page + 0x800, 0xFF, 64); + + info->flags |= PAGE_INITIALIZED; +} + +static void nand_erase_page(uint8_t *page) +{ + PAGEInfo *info = page_info(page); + + /* erase page data */ + memset(page, 0xFF, 0x800); + /* erase OOB data */ + memset(page + 0x800, 0xFF, 64); + + info->page_erases++; + info->flags |= PAGE_CLEAN; +} + + + +static int nand_read_page(CAFEState *s, + int index, int block, int page) +{ + PAGEInfo *info = page_info(s->page_buf); + int64_t secnum = ((block * 64) + page) * 5; + int ret; + + ret = bdrv_read(s->nand[index].bds, secnum, s->page_buf, 5); + + /* async I/O splits here ... */ + nand_log("read page %03x:%02x = %d [%x]", + block, page, ret, info->flags); + + if (!(info->flags & PAGE_INITIALIZED)) + nand_init_page(s->page_buf); + + s->ecc_code = info->ecc_code; + s->ecc_read = info->ecc_read; + s->ecc_result = info->ecc_result; + s->syndrome[0] = info->syndrome[0]; + s->syndrome[1] = info->syndrome[1]; + s->syndrome[2] = info->syndrome[2]; + s->syndrome[3] = info->syndrome[3]; + + if (ret < 0) + nand_log("bdrv_read: error %d", ret); + + /* FIXME: get page flags */ + s->nand[index].status = 0xe0; + return 0; +} + +static int nand_write_page(CAFEState *s, + int index, int block, int page) +{ + PAGEInfo *info = page_info(s->page_buf); + int64_t secnum = ((block * 64) + page) * 5; + int ret; + + ret = bdrv_write(s->nand[index].bds, secnum, s->page_buf, 5); + nand_log("write page %03x:%02x = %d", block, page, ret); + if (ret < 0) + nand_log("bdrv_write: error %d", ret); + + /* FIXME: get page flags */ + s->nand[index].status = 0xe0; + return 0; +} + +static int nand_erase_block(CAFEState *s, + int index, int block) +{ + PAGEInfo *info = page_info(s->page_buf); + int64_t secnum = (block * 64) * 5; + int ret, page; + + nand_log("erase block %03x", block); + printf("··· erase block %03x\n", block); + + for (page=0; page<64; page++) { + nand_read_page(s, index, block, page); + nand_erase_page(s->page_buf); + + info->flags |= PAGE_CLEAN; + info->flags &= ~PAGE_PROGRAMMED; + nand_write_page(s, index, block, page); + } + + /* FIXME: get block flags */ + s->nand[index].status = 0xe0; + return 0; +} + +static inline unsigned page_from_addr(uint8_t addr[5]) +{ + return addr[2] & 0x3F; +} + +static inline unsigned block_from_addr(uint8_t addr[5]) +{ + return (addr[2] >> 6) | (addr[3] << 2) | (addr[4] << 10); +} + +static inline unsigned offset_from_addr(uint8_t addr[5]) +{ + return addr[0] | (addr[1] << 8); +} + + +static inline unsigned index_from_addr(uint8_t addr[3]) +{ + return addr[0] | (addr[1] << 8) | (addr[2] << 16); +} + + + +static void nand_cmd(CAFEState *s, + uint8_t *rbuf, uint8_t *wbuf, int len, + int cmd, uint8_t addr[5]) +{ + switch (cmd) { + case 0x70: /* READ STATUS REGISTER */ + /* HY27UF084G2M */ + wbuf[0] = s->nand[0].status; + break; + + case 0x90: /* READ ID */ + /* HY27UF084G2M */ + wbuf[0] = 0xAD; wbuf[1] = 0xDC; + wbuf[2] = 0x80; wbuf[3] = 0x95; + break; + + case 0xFF: /* RESET */ + break; + + default: + nand_log("unknown cmd %02x", cmd); + } +} + +static void nand_cmd2(CAFEState *s, + uint8_t *rbuf, uint8_t *wbuf, int len, + int cmd, int cmd2, uint8_t addr[5]) +{ + PAGEInfo *info = page_info(s->page_buf); + + switch ((cmd << 8) | cmd2) { + case 0x8010: /* PAGE PROGRAM */ + nand_log("program %02x:%02x:%02x %02x:%02x", + addr[4], addr[3], addr[2], addr[1], addr[0]); + + /* avoid reloading the page if already present */ + nand_read_page(s, 0 /* chip */, + block_from_addr(addr), page_from_addr(addr)); + + /* FIXME: we want some sanity checks here */ + + memcpy(s->page_buf + offset_from_addr(addr), wbuf, len); + + info->flags |= PAGE_PROGRAMMED; + nand_write_page(s, 0 /* chip */, + block_from_addr(addr), page_from_addr(addr)); + break; + + case 0x0030: /* READ 1 */ + nand_log("read %02x:%02x:%02x %02x:%02x", + addr[4], addr[3], addr[2], addr[1], addr[0]); + + nand_read_page(s, 0 /* chip */, + block_from_addr(addr), page_from_addr(addr)); + + /* FIXME: we want some sanity checks here */ + memcpy(rbuf, s->page_buf + offset_from_addr(addr), len); + break; + + case 0x60d0: /* BLOCK ERASE */ + nand_log("block erase %02x:%02x:%02x", + addr[2], addr[1], addr[0]); + + nand_erase_block(s, 0 /* chip */, + index_from_addr(addr)/0x40); + break; + + default: + nand_log("unknown cmd/2 %02x:%02x", cmd, cmd2); + } +} + +static void cafe_dma_write(CAFEState *s) +{ + int len = s->dma_ctrl & 0x0FFF; + target_phys_addr_t addr = + ((uint64_t)s->dma_addr1 << 32) | s->dma_addr0; + + cafe_log("dma write %08lx [%d]", addr, len); + + cpu_physical_memory_read(addr, s->dma_buf, len); + + s->irq |= (1 << 28); /* dma done. */ +} + +static void cafe_dma_read(CAFEState *s) +{ + int len = s->dma_ctrl & 0x0FFF; + int dlen = s->data_len & 0x0FFF; + target_phys_addr_t addr = + ((uint64_t)s->dma_addr1 << 32) | s->dma_addr0; + + cafe_log("dma read %08lx [%d,%d]", addr, len, dlen); + + cpu_physical_memory_write(addr, s->dma_buf, len); + + if (dlen > len) { + int slen = dlen - len; + + if (slen > sizeof(s->pio_read)) + slen = sizeof(s->pio_read); + + cafe_log("dma read %08lx spilled [%d]", addr, slen); + memcpy(s->pio_read, s->dma_buf + len, slen); + } + + s->irq |= (1 << 28); /* dma done. */ +} + + +static void cafe_do_cmd(CAFEState *s) +{ + int cmd = s->ctrl & 0xFF; + int cmd2 = s->ctrl2 & 0xFF; + int len = s->data_len & 0xFFFFFF; + + int nomem = ((s->ctrl >> 20) & 0x1) | + (((s->ctrl >> 22) & 0x7) << 1); + int is_write = s->ctrl & (1 << 25); + int is_read = s->ctrl & (1 << 26); + int cycles = (s->ctrl >> 27) & 0x7; + int do_addr = s->ctrl & (1 << 30); + + int do_ecc = s->ctrl2 & (1 << 30); + int page_size = (s->ctrl2 >> 28) & 0x3; + int do_rs = s->ctrl2 & (1 << 27); + int do_cmd2 = s->ctrl2 & (1 << 8); + int do_reset = s->ctrl3 & (1 << 31); + int write_enable = s->ctrl3 & (1 << 30); + + int is_dma = s->dma_ctrl & (1 << 31); + int dma_read = s->dma_ctrl & (1 << 29); + int dma_len = s->dma_ctrl & 0xFFF; + + uint8 *rbuf = is_dma ? s->dma_buf : s->pio_read; + uint8 *wbuf = is_dma ? s->dma_buf : s->pio_write; + + + uint8 addr[5] = { + s->col_addr & 0xFF, (s->col_addr >> 8) & 0xFF, + s->row_addr & 0xFF, (s->row_addr >> 8) & 0xFF, + (s->row_addr >> 16) & 0xFF }; + + nand_log("cmd %02x,%02x [%d,%d] %s-%s", + cmd, cmd2, nomem, cycles, + is_read?"read":"*", is_write?"write":"*"); + + if (is_dma && !dma_read && dma_len) + cafe_dma_write(s); + + if (do_cmd2) + nand_cmd2(s, rbuf, wbuf, len, cmd, cmd2, addr); + else + nand_cmd(s, rbuf, wbuf, len, cmd, addr); + + if (is_dma && dma_read && dma_len) + cafe_dma_read(s); + + s->irq |= (1 << 31); /* cmd done. */ + cafe_update_irq(s); +} + + +#define VALUE_WRITE(a,n,v) CAFE_##a: s->n = (v); break + +static void cafe_writel(void *opaque, uint32_t addr, uint32_t value) +{ + CAFEState *s = (CAFEState *)opaque; + + addr &= PCI_MEM_MASK; + + switch (addr) { + case CAFE_NAND_CTRL1: + s->ctrl = value; + if (value & (1 << 31)) + cafe_do_cmd(s); + break; + + case VALUE_WRITE(NAND_CTRL2, ctrl2, value); + case VALUE_WRITE(NAND_CTRL3, ctrl3, value); + + // case CAFE_NAND_STATUS: + + case CAFE_NAND_IRQ: + /* write clears bit */ + s->irq &= ~value; + break; + + case VALUE_WRITE(NAND_IRQ_MASK, irq_mask, value); + + case VALUE_WRITE(NAND_DATA_LEN, data_len, value); + case VALUE_WRITE(NAND_ADDR1, col_addr, value & 0xFFFF); + case VALUE_WRITE(NAND_ADDR2, row_addr, value & 0xFFFFFF); + + case CAFE_NAND_TIMING1: + case CAFE_NAND_TIMING2: + case CAFE_NAND_TIMING3: + /* nothing of interest */ + break; + + // case CAFE_NAND_NONMEM: + // case CAFE_NAND_ECC_RESULT: + // break; + + case VALUE_WRITE(NAND_DMA_CTRL, dma_ctrl, value); + case VALUE_WRITE(NAND_DMA_ADDR0, dma_addr0, value); + case VALUE_WRITE(NAND_DMA_ADDR1, dma_addr1, value); + + // case CAFE_NAND_ECC_SYN01: + // case CAFE_NAND_ECC_SYN23: + // case CAFE_NAND_ECC_SYN45: + // case CAFE_NAND_ECC_SYN67: + // case CAFE_NAND_READ_DATA: + // case CAFE_NAND_WRITE_DATA: + + case CAFE_GLOBAL_CTRL: + /* mitch: nothing of interest */ + break; + + // case CAFE_GLOBAL_IRQ: + break; + case VALUE_WRITE(GLOBAL_IRQ_MASK, global_irq_mask, value); + + case CAFE_NAND_RESET: + if (value & 0x1) + cafe_reset(s); + break; + + default: + cafe_log("unhandled write %04x = %08x", addr, value); + break; + } +} + + +#define VALUE_READ(a,n) CAFE_##a: value = s->n; break + +static uint32_t cafe_readl(void *opaque, uint32_t addr) +{ + CAFEState *s = (CAFEState *)opaque; + uint32_t value = 0; + + addr &= PCI_MEM_MASK; + + switch (addr) { + case VALUE_READ(NAND_CTRL1, ctrl); + case VALUE_READ(NAND_CTRL2, ctrl2); + case VALUE_READ(NAND_CTRL3, ctrl3); + + case VALUE_READ(NAND_STATUS, status); + case VALUE_READ(NAND_IRQ, irq); + case VALUE_READ(NAND_IRQ_MASK, irq_mask); + case VALUE_READ(NAND_DATA_LEN, data_len); + case VALUE_READ(NAND_ADDR1, col_addr); + case VALUE_READ(NAND_ADDR2, row_addr); + + case CAFE_NAND_TIMING1: + case CAFE_NAND_TIMING2: + case CAFE_NAND_TIMING3: + break; + + // case CAFE_NAND_NONMEM: + + case VALUE_READ(NAND_ECC_CODE, ecc_code); + case VALUE_READ(NAND_ECC_READ, ecc_read); + case VALUE_READ(NAND_ECC_RESULT, ecc_result); + + // case CAFE_NAND_DMA_CTRL: + case VALUE_READ(NAND_DMA_ADDR0, dma_addr0); + case VALUE_READ(NAND_DMA_ADDR1, dma_addr1); + + case VALUE_READ(NAND_ECC_SYN01, syndrome[0]); + case VALUE_READ(NAND_ECC_SYN23, syndrome[1]); + case VALUE_READ(NAND_ECC_SYN45, syndrome[2]); + case VALUE_READ(NAND_ECC_SYN67, syndrome[3]); + + /* FIXME: pio unhandled */ + // case CAFE_NAND_READ_DATA: + // case CAFE_NAND_WRITE_DATA: + + case CAFE_GLOBAL_CTRL: + /* mitch: ignore */ + break; + + case CAFE_GLOBAL_IRQ: + value = (s->irq & (1 << 31)) ? ((1 << 31) | 1) : 0; + break; + + case VALUE_READ(GLOBAL_IRQ_MASK, global_irq_mask); + + case CAFE_NAND_RESET: + break; + + default: + cafe_log("unhandled read %04x", addr); + break; + } + + return value; +} + +static void cafe_writew(void *opaque, uint32_t addr, uint32_t value) +{ + addr &= PCI_MEM_MASK; + cafe_log("write [w]: %04x = %04x", addr, value); +} + +static void cafe_writeb(void *opaque, uint32_t addr, uint32_t value) +{ + addr &= PCI_MEM_MASK; + cafe_log("write [b]: %04x = %02x", addr, value); +} + +static uint32_t cafe_readw(void *opaque, uint32_t addr) +{ + uint32_t value = 0; + + addr &= PCI_MEM_MASK; + + cafe_log("read [w]: %04x = %08x", addr, value); + return value; +} + +static uint32_t cafe_readb(void *opaque, uint32_t addr) +{ + uint32_t value = 0; + + addr &= PCI_MEM_MASK; + + cafe_log("read [b]: %04x = %08x", addr, value); + return value; +} + +#if 0 +static void cafe_io_map(PCIDevice *pci_dev, + int region_num, uint32_t addr, uint32_t size, int type) +{ + CAFEState *s = (CAFEState *)pci_dev; + + register_ioport_write(addr, PCI_IO_SIZE, 4, cafe_writel, s); + register_ioport_write(addr, PCI_IO_SIZE, 2, cafe_writew, s); + register_ioport_write(addr, PCI_IO_SIZE, 1, cafe_writeb, s); + + register_ioport_read(addr, PCI_IO_SIZE, 4, cafe_readl, s); + register_ioport_read(addr, PCI_IO_SIZE, 2, cafe_readw, s); + register_ioport_read(addr, PCI_IO_SIZE, 1, cafe_readb, s); +} +#endif + + +static void cafe_mem_writeb(void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + cafe_writeb(opaque, addr, val); +} + +static void cafe_mem_writew(void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + cafe_writew(opaque, addr, val); +} + +static void cafe_mem_writel(void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + cafe_writel(opaque, addr, val); +} + +static uint32_t cafe_mem_readb(void *opaque, target_phys_addr_t addr) +{ + return cafe_readb(opaque, addr); +} + +static uint32_t cafe_mem_readw(void *opaque, target_phys_addr_t addr) +{ + return cafe_readw(opaque, addr); +} + +static uint32_t cafe_mem_readl(void *opaque, target_phys_addr_t addr) +{ + return cafe_readl(opaque, addr); +} + + +static CPUReadMemoryFunc *cafe_mem_read[3] = { + cafe_mem_readb, + cafe_mem_readw, + cafe_mem_readl, +}; + +static CPUWriteMemoryFunc *cafe_mem_write[3] = { + cafe_mem_writeb, + cafe_mem_writew, + cafe_mem_writel, +}; + + +static void cafe_mem_map(PCIDevice *pci_dev, + int region_num, uint32_t addr, uint32_t size, int type) +{ + CAFEState *s = (CAFEState *)pci_dev; + + cafe_log("register memory [%d]: %08x[%04x,%d] %08x", + region_num, addr, size, type, s->mmio); + if (region_num == 0) { + cpu_register_physical_memory(addr, size, s->mmio); + } +} + +void cafe_init(PCIBus *bus, int devfn, BlockDriverState **nas) +{ + CAFEState *s; + int i; + + s = (CAFEState *)pci_register_device(bus, + "FLASH memory", sizeof(CAFEState), devfn, NULL, NULL); + + + s->pio_read = qemu_mallocz(CAFE_PIO_READ_SIZE); + s->pio_write = qemu_mallocz(CAFE_PIO_WRITE_SIZE); + s->dma_buf = qemu_mallocz(CAFE_DMA_BUF_SIZE); + s->page_buf = qemu_mallocz(CAFE_PAGE_BUF_SIZE); + + for (i=0; inand[i].status = 0; + s->nand[i].bds = nas[i]; + } + + cafe_pci_reset(s); + cafe_reset(s); + + +#if 0 + /* PCI I/O Region */ + pci_register_io_region(&s->dev, 0, PCI_IO_SIZE, + PCI_ADDRESS_SPACE_IO, cafe_io_map); +#endif + + /* PCI Memory Region */ + s->mmio = cpu_register_io_memory(0, + cafe_mem_read, cafe_mem_write, s); + pci_register_io_region(&s->dev, 0, PCI_MEM_SIZE, + PCI_ADDRESS_SPACE_MEM, cafe_mem_map); + +#if 0 + register_savevm("cafe_pci", 0, 1, + cafe_save, cafe_load, &s->dev); +#endif + +} + diff -NurpP --minimal -x '*softmmu' -x '*user' qemu-0.9.0/hw/pc.c qemu-0.9.0-olpc_v01/hw/pc.c --- qemu-0.9.0/hw/pc.c 2007-02-05 18:01:54.000000000 -0500 +++ qemu-0.9.0-olpc_v01/hw/pc.c 2007-02-10 21:31:29.000000000 -0500 @@ -707,6 +707,10 @@ static void pc_init1(int ram_size, int v piix4_smbus_register_device(eeprom, 0x50 + i); } } + + if (pci_enabled) { + cafe_init(pci_bus, -1, na_table); + } if (i440fx_state) { i440fx_init_memory_mappings(i440fx_state); diff -NurpP --minimal -x '*softmmu' -x '*user' qemu-0.9.0/Makefile.target qemu-0.9.0-olpc_v01/Makefile.target --- qemu-0.9.0/Makefile.target 2007-02-05 18:01:54.000000000 -0500 +++ qemu-0.9.0-olpc_v01/Makefile.target 2007-02-10 00:40:22.000000000 -0500 @@ -370,7 +370,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o piix_pci.o -VL_OBJS+= usb-uhci.o smbus_eeprom.o +VL_OBJS+= usb-uhci.o smbus_eeprom.o cafe_pci.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) diff -NurpP --minimal -x '*softmmu' -x '*user' qemu-0.9.0/monitor.c qemu-0.9.0-olpc_v01/monitor.c --- qemu-0.9.0/monitor.c 2007-02-05 18:01:54.000000000 -0500 +++ qemu-0.9.0-olpc_v01/monitor.c 2007-02-11 02:34:27.000000000 -0500 @@ -207,6 +207,13 @@ static void do_commit(const char *device bdrv_commit(bs_table[i]); } } + for (i = 0; i < MAX_NAND; i++) { + if (na_table[i]) { + if (all_devices || + !strcmp(bdrv_get_device_name(na_table[i]), device)) + bdrv_commit(na_table[i]); + } + } } static void do_info(const char *item) diff -NurpP --minimal -x '*softmmu' -x '*user' qemu-0.9.0/vl.c qemu-0.9.0-olpc_v01/vl.c --- qemu-0.9.0/vl.c 2007-02-05 18:01:54.000000000 -0500 +++ qemu-0.9.0-olpc_v01/vl.c 2007-02-11 02:33:01.000000000 -0500 @@ -122,6 +122,7 @@ IOPortWriteFunc *ioport_write_table[3][M /* Note: bs_table[MAX_DISKS] is a dummy block driver if none available to store the VM snapshots */ BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; +BlockDriverState *na_table[MAX_NAND]; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; int vga_ram_size; @@ -1455,6 +1456,15 @@ static void stdio_received_byte(int ch) case 'x': exit(0); break; + case 'n': + { + int i; + for (i = 0; i < MAX_NAND; i++) { + if (na_table[i]) + bdrv_commit(na_table[i]); + } + } + break; case 's': { int i; @@ -6153,6 +6163,7 @@ enum { QEMU_OPTION_hdb, QEMU_OPTION_hdc, QEMU_OPTION_hdd, + QEMU_OPTION_nand, QEMU_OPTION_cdrom, QEMU_OPTION_boot, QEMU_OPTION_snapshot, @@ -6225,6 +6236,7 @@ const QEMUOption qemu_options[] = { { "hdb", HAS_ARG, QEMU_OPTION_hdb }, { "hdc", HAS_ARG, QEMU_OPTION_hdc }, { "hdd", HAS_ARG, QEMU_OPTION_hdd }, + { "nand", HAS_ARG, QEMU_OPTION_nand }, { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, @@ -6505,6 +6517,7 @@ int main(int argc, char **argv) int snapshot, linux_boot; const char *initrd_filename; const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; + const char *na_filename[MAX_NAND]; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; @@ -6562,6 +6575,8 @@ int main(int argc, char **argv) fd_filename[i] = NULL; for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; + for(i = 0; i < MAX_NAND; i++) + na_filename[i] = NULL; ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; bios_size = BIOS_SIZE; @@ -6664,6 +6679,9 @@ int main(int argc, char **argv) cdrom_index = -1; } break; + case QEMU_OPTION_nand: + na_filename[0] = optarg; + break; case QEMU_OPTION_snapshot: snapshot = 1; break; @@ -7145,6 +7163,22 @@ int main(int argc, char **argv) } } + /* open the virtual nand devices */ + for(i = 0; i < MAX_NAND; i++) { + if (na_filename[i]) { + if (!na_table[i]) { + char buf[64]; + snprintf(buf, sizeof(buf), "nand%d", i); + na_table[i] = bdrv_new(buf); + } + if (bdrv_open(na_table[i], na_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { + fprintf(stderr, "qemu: could not open nand image '%s'\n", + na_filename[i]); + exit(1); + } + } + } + register_savevm("timer", 0, 2, timer_save, timer_load, NULL); register_savevm("ram", 0, 2, ram_save, ram_load, NULL); diff -NurpP --minimal -x '*softmmu' -x '*user' qemu-0.9.0/vl.h qemu-0.9.0-olpc_v01/vl.h --- qemu-0.9.0/vl.h 2007-02-05 18:01:54.000000000 -0500 +++ qemu-0.9.0-olpc_v01/vl.h 2007-02-10 22:01:08.000000000 -0500 @@ -1369,6 +1369,13 @@ pflash_t *pflash_register (target_ulong uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3); +/* cafe_pci.c */ + +#define MAX_NAND 1 +extern BlockDriverState *na_table[MAX_NAND]; + +void cafe_init(PCIBus *bus, int devfn, BlockDriverState **nas); + #include "gdbstub.h" #endif /* defined(QEMU_TOOL) */