From e9e5d0828ce4e00486aba26ee735afeaa0176ff1 Mon Sep 17 00:00:00 2001 From: Michel Date: Mon, 23 Feb 2009 15:38:09 +0000 Subject: [PATCH] [S3C] Split nand driver out of s3c Removed the s2410 driver from the main CPU file, and made it modular, with a small driver interface. This was done because the NAND interface is pretty much the major differing subsystem between a 2410 and 2440 --- hw/mini2440.c | 2 +- hw/s3c.h | 22 +++---- hw/s3c2410.c | 152 ++------------------------------------------ hw/s3c2410_nand.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+), 159 deletions(-) create mode 100644 hw/s3c2410_nand.c diff --git a/hw/mini2440.c b/hw/mini2440.c index 725677d7af..4a0d10936b 100644 --- a/hw/mini2440.c +++ b/hw/mini2440.c @@ -176,7 +176,7 @@ static void mini2440_init(ram_addr_t ram_size, int vga_ram_size, neo = mini2440_init_common(ram_size, ds, kernel_filename, cpu_model, sd, MACH_MINI2440); - s3c_nand_register(neo->cpu, nand_init(NAND_MFR_SAMSUNG, 0xa2)); + neo->cpu->nand->reg(neo->cpu->nand, nand_init(NAND_MFR_SAMSUNG, 0xa2)); } diff --git a/hw/s3c.h b/hw/s3c.h index 84874b7590..b6abf2c913 100644 --- a/hw/s3c.h +++ b/hw/s3c.h @@ -175,6 +175,15 @@ struct s3c_udc_state_s *s3c_udc_init(target_phys_addr_t base, qemu_irq irq, qemu_irq *dma); void s3c_udc_reset(struct s3c_udc_state_s *s); +struct s3c_nand_driver_s { + void (*reset)(void * opaque); + void (*setwp)(void * opaque, int wp); + void (*reg)(void * opaque, struct nand_flash_s *chip); +}; + +/* s3c2410_nand.c */ +struct s3c_nand_driver_s * s3c2410_nand_init(); + /* s3c2410.c */ struct s3c_spi_state_s; struct s3c_spi_state_s *s3c_spi_init(target_phys_addr_t base, @@ -203,20 +212,12 @@ struct s3c_state_s { struct s3c_spi_state_s *spi; struct s3c_udc_state_s *udc; struct s3c_wdt_state_s *wdt; + struct s3c_nand_driver_s *nand; /* Memory controller */ target_phys_addr_t mc_base; uint32_t mc_regs[13]; - /* NAND Flash controller */ - target_phys_addr_t nand_base; - struct nand_flash_s *nand; - uint16_t nfconf; - uint8_t nfcmd; - uint8_t nfaddr; - struct ecc_state_s nfecc; - int nfwp; - /* Clock & power management */ target_phys_addr_t clkpwr_base; uint32_t clkpwr_regs[6]; @@ -225,8 +226,7 @@ struct s3c_state_s { /* s3c2410.c */ struct s3c_state_s *s3c24xx_init(uint32_t cpu_id, unsigned int sdram_size, DisplayState *ds, SDState *mmc); -void s3c_nand_register(struct s3c_state_s *s, struct nand_flash_s *chip); -void s3c_nand_setwp(struct s3c_state_s *s, int wp); + struct s3c_i2s_state_s { /* XXX move to .c */ target_phys_addr_t base; diff --git a/hw/s3c2410.c b/hw/s3c2410.c index 355b246dab..e487aa4643 100644 --- a/hw/s3c2410.c +++ b/hw/s3c2410.c @@ -443,145 +443,6 @@ static int s3c_mc_load(QEMUFile *f, void *opaque, int version_id) return 0; } -/* NAND Flash controller */ -#define S3C_NFCONF 0x00 /* NAND Flash Configuration register */ -#define S3C_NFCMD 0x04 /* NAND Flash Command Set register */ -#define S3C_NFADDR 0x08 /* NAND Flash Address Set register */ -#define S3C_NFDATA 0x0c /* NAND Flash Data register */ -#define S3C_NFSTAT 0x10 /* NAND Flash Operation Status register */ -#define S3C_NFECC 0x14 /* NAND Flash ECC register */ - -static void s3c_nand_reset(struct s3c_state_s *s) -{ - s->nfconf = 0; - s->nfcmd = 0; - s->nfaddr = 0; - ecc_reset(&s->nfecc); -} - -static uint32_t s3c_nand_read(void *opaque, target_phys_addr_t addr) -{ - struct s3c_state_s *s = (struct s3c_state_s *) opaque; - int rb, shr = 0; - if (!s->nand) - return 0; - addr -= s->nand_base; - - switch (addr) { - case S3C_NFCONF: - return s->nfconf; - case S3C_NFCMD: - return s->nfcmd; - case S3C_NFADDR: - return s->nfaddr; - case S3C_NFDATA: - if (s->nfconf & (1 << 15)) - return ecc_digest(&s->nfecc, nand_getio(s->nand)); - break; - case S3C_NFSTAT: - nand_getpins(s->nand, &rb); - return rb; - case S3C_NFECC + 2: shr += 8; - case S3C_NFECC + 1: shr += 8; - case S3C_NFECC: -#define ECC(shr, b, shl) ((s->nfecc.lp[b] << (shl - shr)) & (1 << shl)) - return (~( - ECC(0, 1, 0) | ECC(0, 0, 1) | ECC(1, 1, 2) | ECC(1, 0, 3) | - ECC(2, 1, 4) | ECC(2, 0, 5) | ECC(3, 1, 6) | ECC(3, 0, 7) | - ECC(4, 1, 8) | ECC(4, 0, 9) | ECC(5, 1, 10) | ECC(5, 0, 11) | - ECC(6, 1, 12) | ECC(6, 0, 13) | ECC(7, 1, 14) | ECC(7, 0, 15) | - ECC(8, 1, 16) | ECC(8, 0, 17) | (s->nfecc.cp << 18)) >> shr) & - 0xff; -#undef ECC - default: - printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr); - break; - } - return 0; -} - -static void s3c_nand_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct s3c_state_s *s = (struct s3c_state_s *) opaque; - if (!s->nand) - return; - addr -= s->nand_base; - - switch (addr) { - case S3C_NFCONF: - s->nfconf = value & 0x9fff; - if (value & (1 << 12)) - ecc_reset(&s->nfecc); - break; - case S3C_NFCMD: - s->nfcmd = value & 0xff; - if (s->nfconf & (1 << 15)) { - nand_setpins(s->nand, 1, 0, (s->nfconf >> 11) & 1, s->nfwp, 0); - nand_setio(s->nand, s->nfcmd); - nand_setpins(s->nand, 0, 0, (s->nfconf >> 11) & 1, s->nfwp, 0); - } - break; - case S3C_NFADDR: - s->nfaddr = value & 0xff; - if (s->nfconf & (1 << 15)) { - nand_setpins(s->nand, 0, 1, (s->nfconf >> 11) & 1, s->nfwp, 0); - nand_setio(s->nand, s->nfaddr); - nand_setpins(s->nand, 0, 0, (s->nfconf >> 11) & 1, s->nfwp, 0); - } - break; - case S3C_NFDATA: - if (s->nfconf & (1 << 15)) - nand_setio(s->nand, ecc_digest(&s->nfecc, value & 0xff)); - break; - default: - printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr); - } -} - -void s3c_nand_register(struct s3c_state_s *s, struct nand_flash_s *chip) -{ - s->nand = chip; -} - -void s3c_nand_setwp(struct s3c_state_s *s, int wp) -{ - s->nfwp = wp; -} - -static CPUReadMemoryFunc *s3c_nand_readfn[] = { - s3c_nand_read, - s3c_nand_read, - s3c_nand_read, -}; - -static CPUWriteMemoryFunc *s3c_nand_writefn[] = { - s3c_nand_write, - s3c_nand_write, - s3c_nand_write, -}; - -static void s3c_nand_save(QEMUFile *f, void *opaque) -{ - struct s3c_state_s *s = (struct s3c_state_s *) opaque; - qemu_put_be16s(f, &s->nfconf); - qemu_put_8s(f, &s->nfcmd); - qemu_put_8s(f, &s->nfaddr); - qemu_put_be32(f, s->nfwp); - ecc_put(f, &s->nfecc); -} - -static int s3c_nand_load(QEMUFile *f, void *opaque, int version_id) -{ - struct s3c_state_s *s = (struct s3c_state_s *) opaque; - qemu_get_be16s(f, &s->nfconf); - qemu_get_8s(f, &s->nfcmd); - qemu_get_8s(f, &s->nfaddr); - s->nfwp = qemu_get_be32(f); - ecc_get(f, &s->nfecc); - return 0; -} - /* Clock & power management */ #define S3C_LOCKTIME 0x00 /* PLL Lock Time Count register */ #define S3C_MPLLCON 0x04 /* MPLL Configuration register */ @@ -2831,7 +2692,8 @@ static void s3c2410_reset(void *opaque) s3c_udc_reset(s->udc); s3c_wdt_reset(s->wdt); s3c_clkpwr_reset(s); - s3c_nand_reset(s); + // s3c_nand_reset(s); + s->nand->reset(s->nand); for (i = 0; s3c2410_uart[i].base; i ++) s3c_uart_reset(s->uart[i]); cpu_reset(s->env); @@ -2880,12 +2742,7 @@ struct s3c_state_s *s3c24xx_init(uint32_t cpu_id, unsigned int sdram_size, Displ s->lcd = s3c_lcd_init(0x4d000000, ds, s->irq[S3C_PIC_LCD]); - s->nand_base = 0x4e000000; - s3c_nand_reset(s); - iomemtype = cpu_register_io_memory(0, s3c_nand_readfn, - s3c_nand_writefn, s); - cpu_register_physical_memory(s->nand_base, 0xffffff, iomemtype); - register_savevm("s3c24xx_nand", 0, 0, s3c_nand_save, s3c_nand_load, s); + s->nand = s3c2410_nand_init(s); for (i = 0; s3c2410_uart[i].base; i ++) { s->uart[i] = s3c_uart_init(s3c2410_uart[i].base, @@ -2925,7 +2782,8 @@ struct s3c_state_s *s3c24xx_init(uint32_t cpu_id, unsigned int sdram_size, Displ qemu_register_reset(s3c2410_reset, s); - s3c_nand_setwp(s, 1); + s->nand->setwp(s->nand, 1); + //s3c_nand_setwp(s, 1); /* Power on reset */ s3c_gpio_setpwrstat(s->io, 1); diff --git a/hw/s3c2410_nand.c b/hw/s3c2410_nand.c new file mode 100644 index 0000000000..9ff7c5644b --- /dev/null +++ b/hw/s3c2410_nand.c @@ -0,0 +1,187 @@ +/* + * Samsung S3C2410A RISC Microprocessor support (ARM920T based SoC). + * + * Copyright (c) 2007 OpenMoko, Inc. + * Author: Andrzej Zaborowski + * With: Michel Pollet + * + * This code is licenced under the GNU GPL v2. + */ + +#include "s3c.h" +#include "hw.h" + +struct s3c2410_nand_s { + struct s3c_nand_driver_s driver; + + /* NAND Flash controller */ + target_phys_addr_t nand_base; + struct nand_flash_s *nand; + uint16_t nfconf; + uint8_t nfcmd; + uint8_t nfaddr; + struct ecc_state_s nfecc; + int nfwp; +}; + +/* NAND Flash controller */ +#define S3C_NFCONF 0x00 /* NAND Flash Configuration register */ +#define S3C_NFCMD 0x04 /* NAND Flash Command Set register */ +#define S3C_NFADDR 0x08 /* NAND Flash Address Set register */ +#define S3C_NFDATA 0x0c /* NAND Flash Data register */ +#define S3C_NFSTAT 0x10 /* NAND Flash Operation Status register */ +#define S3C_NFECC 0x14 /* NAND Flash ECC register */ + +static void s3c2410_nand_reset(void * opaque) +{ + struct s3c2410_nand_s *s = (struct s3c2410_nand_s *)opaque; + s->nfconf = 0; + s->nfcmd = 0; + s->nfaddr = 0; + ecc_reset(&s->nfecc); +} + +static uint32_t s3c2410_nand_read(void *opaque, target_phys_addr_t addr) +{ + struct s3c2410_nand_s *s = (struct s3c2410_nand_s *) opaque; + int rb, shr = 0; + if (!s->nand) + return 0; + addr -= s->nand_base; + + switch (addr) { + case S3C_NFCONF: + return s->nfconf; + case S3C_NFCMD: + return s->nfcmd; + case S3C_NFADDR: + return s->nfaddr; + case S3C_NFDATA: + if (s->nfconf & (1 << 15)) + return ecc_digest(&s->nfecc, nand_getio(s->nand)); + break; + case S3C_NFSTAT: + nand_getpins(s->nand, &rb); + return rb; + case S3C_NFECC + 2: shr += 8; + case S3C_NFECC + 1: shr += 8; + case S3C_NFECC: +#define ECC(shr, b, shl) ((s->nfecc.lp[b] << (shl - shr)) & (1 << shl)) + return (~( + ECC(0, 1, 0) | ECC(0, 0, 1) | ECC(1, 1, 2) | ECC(1, 0, 3) | + ECC(2, 1, 4) | ECC(2, 0, 5) | ECC(3, 1, 6) | ECC(3, 0, 7) | + ECC(4, 1, 8) | ECC(4, 0, 9) | ECC(5, 1, 10) | ECC(5, 0, 11) | + ECC(6, 1, 12) | ECC(6, 0, 13) | ECC(7, 1, 14) | ECC(7, 0, 15) | + ECC(8, 1, 16) | ECC(8, 0, 17) | (s->nfecc.cp << 18)) >> shr) & + 0xff; +#undef ECC + default: + printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr); + break; + } + return 0; +} + +static void s3c2410_nand_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct s3c2410_nand_s *s = (struct s3c2410_nand_s *) opaque; + if (!s->nand) + return; + addr -= s->nand_base; + + switch (addr) { + case S3C_NFCONF: + s->nfconf = value & 0x9fff; + if (value & (1 << 12)) + ecc_reset(&s->nfecc); + break; + case S3C_NFCMD: + s->nfcmd = value & 0xff; + if (s->nfconf & (1 << 15)) { + nand_setpins(s->nand, 1, 0, (s->nfconf >> 11) & 1, s->nfwp, 0); + nand_setio(s->nand, s->nfcmd); + nand_setpins(s->nand, 0, 0, (s->nfconf >> 11) & 1, s->nfwp, 0); + } + break; + case S3C_NFADDR: + s->nfaddr = value & 0xff; + if (s->nfconf & (1 << 15)) { + nand_setpins(s->nand, 0, 1, (s->nfconf >> 11) & 1, s->nfwp, 0); + nand_setio(s->nand, s->nfaddr); + nand_setpins(s->nand, 0, 0, (s->nfconf >> 11) & 1, s->nfwp, 0); + } + break; + case S3C_NFDATA: + if (s->nfconf & (1 << 15)) + nand_setio(s->nand, ecc_digest(&s->nfecc, value & 0xff)); + break; + default: + printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr); + } +} + +void s3c2410_nand_register(void * opaque, struct nand_flash_s *chip) +{ + struct s3c2410_nand_s *s = (struct s3c2410_nand_s *) opaque; + s->nand = chip; +} + +void s3c2410_nand_setwp(void * opaque, int wp) +{ + struct s3c2410_nand_s *s = (struct s3c2410_nand_s *) opaque; + s->nfwp = wp; +} + +static CPUReadMemoryFunc *s3c2410_nand_readfn[] = { + s3c2410_nand_read, + s3c2410_nand_read, + s3c2410_nand_read, +}; + +static CPUWriteMemoryFunc *s3c2410_nand_writefn[] = { + s3c2410_nand_write, + s3c2410_nand_write, + s3c2410_nand_write, +}; + +static void s3c2410_nand_save(QEMUFile *f, void *opaque) +{ + struct s3c2410_nand_s *s = (struct s3c2410_nand_s *) opaque; + qemu_put_be16s(f, &s->nfconf); + qemu_put_8s(f, &s->nfcmd); + qemu_put_8s(f, &s->nfaddr); + qemu_put_be32(f, s->nfwp); + ecc_put(f, &s->nfecc); +} + +static int s3c2410_nand_load(QEMUFile *f, void *opaque, int version_id) +{ + struct s3c2410_nand_s *s = (struct s3c2410_nand_s *) opaque; + qemu_get_be16s(f, &s->nfconf); + qemu_get_8s(f, &s->nfcmd); + qemu_get_8s(f, &s->nfaddr); + s->nfwp = qemu_get_be32(f); + ecc_get(f, &s->nfecc); + return 0; +} + +static const struct s3c_nand_driver_s s3c2410_nand_driver = { + .reset = s3c2410_nand_reset, + .setwp = s3c2410_nand_setwp, + .reg = s3c2410_nand_register +}; + +struct s3c_nand_driver_s * s3c2410_nand_init() +{ + int iomemtype; + struct s3c2410_nand_s *nand = (struct s3c2410_nand_s *) + qemu_mallocz(sizeof(struct s3c2410_nand_s)); + nand->driver = s3c2410_nand_driver; + nand->nand_base = 0x4e000000; + nand->driver.reset(nand); + iomemtype = cpu_register_io_memory(0, s3c2410_nand_readfn, s3c2410_nand_writefn, nand); + cpu_register_physical_memory(nand->nand_base, 0xffffff, iomemtype); + register_savevm("s3c24xxb10_nand", 0, 0, s3c2410_nand_save, s3c2410_nand_load, nand); + return &nand->driver; +} -- 2.11.4.GIT