x49gp/s3c2410_usbdev.c

342 lines
9 KiB
C

/* $Id: s3c2410_usbdev.c,v 1.4 2008/12/11 12:18:17 ecd Exp $
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <x49gp.h>
#include <s3c2410.h>
typedef struct {
uint32_t func_addr_reg;
uint32_t pwr_reg;
uint32_t ep_int_reg;
uint32_t usb_int_reg;
uint32_t ep_int_en_reg;
uint32_t usb_int_en_reg;
uint32_t frame_num1_reg;
uint32_t frame_num2_reg;
uint32_t index_reg;
uint32_t ep0_fifo_reg;
uint32_t ep1_fifo_reg;
uint32_t ep2_fifo_reg;
uint32_t ep3_fifo_reg;
uint32_t ep4_fifo_reg;
uint32_t ep1_dma_con;
uint32_t ep1_dma_unit;
uint32_t ep1_dma_fifo;
uint32_t ep1_dma_ttc_l;
uint32_t ep1_dma_ttc_m;
uint32_t ep1_dma_ttc_h;
uint32_t ep2_dma_con;
uint32_t ep2_dma_unit;
uint32_t ep2_dma_fifo;
uint32_t ep2_dma_ttc_l;
uint32_t ep2_dma_ttc_m;
uint32_t ep2_dma_ttc_h;
uint32_t ep3_dma_con;
uint32_t ep3_dma_unit;
uint32_t ep3_dma_fifo;
uint32_t ep3_dma_ttc_l;
uint32_t ep3_dma_ttc_m;
uint32_t ep3_dma_ttc_h;
uint32_t ep4_dma_con;
uint32_t ep4_dma_unit;
uint32_t ep4_dma_fifo;
uint32_t ep4_dma_ttc_l;
uint32_t ep4_dma_ttc_m;
uint32_t ep4_dma_ttc_h;
uint32_t __wrong_maxp_reg;
uint32_t in_csr1_reg_ep0_csr;
uint32_t in_csr2_reg;
uint32_t maxp_reg;
uint32_t out_csr1_reg;
uint32_t out_csr2_reg;
uint32_t out_fifo_cnt1_reg;
uint32_t out_fifo_cnt2_reg;
unsigned int nr_regs;
s3c2410_offset_t *regs;
} s3c2410_usbdev_t;
static int
s3c2410_usbdev_data_init(s3c2410_usbdev_t *usbdev)
{
s3c2410_offset_t regs[] = {
S3C2410_OFFSET(USBDEV, FUNC_ADDR_REG, 0x00, usbdev->func_addr_reg),
S3C2410_OFFSET(USBDEV, PWR_REG, 0x00, usbdev->pwr_reg),
S3C2410_OFFSET(USBDEV, EP_INT_REG, 0x00, usbdev->ep_int_reg),
S3C2410_OFFSET(USBDEV, USB_INT_REG, 0x00, usbdev->usb_int_reg),
S3C2410_OFFSET(USBDEV, EP_INT_EN_REG, 0xff, usbdev->ep_int_en_reg),
S3C2410_OFFSET(USBDEV, USB_INT_EN_REG, 0x04, usbdev->usb_int_en_reg),
S3C2410_OFFSET(USBDEV, FRAME_NUM1_REG, 0x00, usbdev->frame_num1_reg),
S3C2410_OFFSET(USBDEV, FRAME_NUM2_REG, 0x00, usbdev->frame_num2_reg),
S3C2410_OFFSET(USBDEV, INDEX_REG, 0x00, usbdev->index_reg),
S3C2410_OFFSET(USBDEV, EP0_FIFO_REG, 0, usbdev->ep0_fifo_reg),
S3C2410_OFFSET(USBDEV, EP1_FIFO_REG, 0, usbdev->ep1_fifo_reg),
S3C2410_OFFSET(USBDEV, EP2_FIFO_REG, 0, usbdev->ep2_fifo_reg),
S3C2410_OFFSET(USBDEV, EP3_FIFO_REG, 0, usbdev->ep3_fifo_reg),
S3C2410_OFFSET(USBDEV, EP4_FIFO_REG, 0, usbdev->ep4_fifo_reg),
S3C2410_OFFSET(USBDEV, EP1_DMA_CON, 0x00, usbdev->ep1_dma_con),
S3C2410_OFFSET(USBDEV, EP1_DMA_UNIT, 0x00, usbdev->ep1_dma_unit),
S3C2410_OFFSET(USBDEV, EP1_DMA_FIFO, 0x00, usbdev->ep1_dma_fifo),
S3C2410_OFFSET(USBDEV, EP1_DMA_TTC_L, 0x00, usbdev->ep1_dma_ttc_l),
S3C2410_OFFSET(USBDEV, EP1_DMA_TTC_M, 0x00, usbdev->ep1_dma_ttc_m),
S3C2410_OFFSET(USBDEV, EP1_DMA_TTC_H, 0x00, usbdev->ep1_dma_ttc_h),
S3C2410_OFFSET(USBDEV, EP2_DMA_CON, 0x00, usbdev->ep2_dma_con),
S3C2410_OFFSET(USBDEV, EP2_DMA_UNIT, 0x00, usbdev->ep2_dma_unit),
S3C2410_OFFSET(USBDEV, EP2_DMA_FIFO, 0x00, usbdev->ep2_dma_fifo),
S3C2410_OFFSET(USBDEV, EP2_DMA_TTC_L, 0x00, usbdev->ep2_dma_ttc_l),
S3C2410_OFFSET(USBDEV, EP2_DMA_TTC_M, 0x00, usbdev->ep2_dma_ttc_m),
S3C2410_OFFSET(USBDEV, EP2_DMA_TTC_H, 0x00, usbdev->ep2_dma_ttc_h),
S3C2410_OFFSET(USBDEV, EP3_DMA_CON, 0x00, usbdev->ep3_dma_con),
S3C2410_OFFSET(USBDEV, EP3_DMA_UNIT, 0x00, usbdev->ep3_dma_unit),
S3C2410_OFFSET(USBDEV, EP3_DMA_FIFO, 0x00, usbdev->ep3_dma_fifo),
S3C2410_OFFSET(USBDEV, EP3_DMA_TTC_L, 0x00, usbdev->ep3_dma_ttc_l),
S3C2410_OFFSET(USBDEV, EP3_DMA_TTC_M, 0x00, usbdev->ep3_dma_ttc_m),
S3C2410_OFFSET(USBDEV, EP3_DMA_TTC_H, 0x00, usbdev->ep3_dma_ttc_h),
S3C2410_OFFSET(USBDEV, EP4_DMA_CON, 0x00, usbdev->ep4_dma_con),
S3C2410_OFFSET(USBDEV, EP4_DMA_UNIT, 0x00, usbdev->ep4_dma_unit),
S3C2410_OFFSET(USBDEV, EP4_DMA_FIFO, 0x00, usbdev->ep4_dma_fifo),
S3C2410_OFFSET(USBDEV, EP4_DMA_TTC_L, 0x00, usbdev->ep4_dma_ttc_l),
S3C2410_OFFSET(USBDEV, EP4_DMA_TTC_M, 0x00, usbdev->ep4_dma_ttc_m),
S3C2410_OFFSET(USBDEV, EP4_DMA_TTC_H, 0x00, usbdev->ep4_dma_ttc_h),
S3C2410_OFFSET(USBDEV, MAXP_REG_WRONG, 0x01, usbdev->__wrong_maxp_reg),
S3C2410_OFFSET(USBDEV, IN_CSR1_REG_EP0_CSR, 0x00, usbdev->in_csr1_reg_ep0_csr),
S3C2410_OFFSET(USBDEV, IN_CSR2_REG, 0x20, usbdev->in_csr2_reg),
S3C2410_OFFSET(USBDEV, MAXP_REG, 0x01, usbdev->maxp_reg),
S3C2410_OFFSET(USBDEV, OUT_CSR1_REG, 0x00, usbdev->out_csr1_reg),
S3C2410_OFFSET(USBDEV, OUT_CSR2_REG, 0x00, usbdev->out_csr2_reg),
S3C2410_OFFSET(USBDEV, OUT_FIFO_CNT1_REG, 0x00, usbdev->out_fifo_cnt1_reg),
S3C2410_OFFSET(USBDEV, OUT_FIFO_CNT2_REG, 0x00, usbdev->out_fifo_cnt2_reg)
};
memset(usbdev, 0, sizeof(s3c2410_usbdev_t));
usbdev->regs = malloc(sizeof(regs));
if (NULL == usbdev->regs) {
fprintf(stderr, "%s:%u: Out of memory\n",
__FUNCTION__, __LINE__);
return -ENOMEM;
}
memcpy(usbdev->regs, regs, sizeof(regs));
usbdev->nr_regs = sizeof(regs) / sizeof(regs[0]);
return 0;
}
static uint32_t
s3c2410_usbdev_read(void *opaque, target_phys_addr_t offset)
{
s3c2410_usbdev_t *usbdev = opaque;
s3c2410_offset_t *reg;
#ifdef QEMU_OLD
offset -= S3C2410_USBDEV_BASE;
#endif
if (! S3C2410_OFFSET_OK(usbdev, offset)) {
return ~(0);
}
reg = S3C2410_OFFSET_ENTRY(usbdev, offset);
#ifdef DEBUG_S3C2410_USBDEV
printf("read %s [%08x] %s [%08x] data %08x\n",
"s3c2410-usbdev", S3C2410_USBDEV_BASE,
reg->name, offset, *(reg->datap));
#endif
return *(reg->datap);
}
static void
s3c2410_usbdev_write(void *opaque, target_phys_addr_t offset, uint32_t data)
{
s3c2410_usbdev_t *usbdev = opaque;
s3c2410_offset_t *reg;
#ifdef QEMU_OLD
offset -= S3C2410_USBDEV_BASE;
#endif
if (! S3C2410_OFFSET_OK(usbdev, offset)) {
return;
}
reg = S3C2410_OFFSET_ENTRY(usbdev, offset);
#ifdef DEBUG_S3C2410_USBDEV
printf("write %s [%08x] %s [%08x] data %08x\n",
"s3c2410-usbdev", S3C2410_USBDEV_BASE,
reg->name, offset, data);
#endif
*(reg->datap) = data;
}
static int
s3c2410_usbdev_load(x49gp_module_t *module, GKeyFile *key)
{
s3c2410_usbdev_t *usbdev = module->user_data;
s3c2410_offset_t *reg;
int error = 0;
int i;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
for (i = 0; i < usbdev->nr_regs; i++) {
reg = &usbdev->regs[i];
if (NULL == reg->name)
continue;
if (x49gp_module_get_u32(module, key, reg->name,
reg->reset, reg->datap))
error = -EAGAIN;
}
return error;
}
static int
s3c2410_usbdev_save(x49gp_module_t *module, GKeyFile *key)
{
s3c2410_usbdev_t *usbdev = module->user_data;
s3c2410_offset_t *reg;
int i;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
for (i = 0; i < usbdev->nr_regs; i++) {
reg = &usbdev->regs[i];
if (NULL == reg->name)
continue;
x49gp_module_set_u32(module, key, reg->name, *(reg->datap));
}
return 0;
}
static int
s3c2410_usbdev_reset(x49gp_module_t *module, x49gp_reset_t reset)
{
s3c2410_usbdev_t *usbdev = module->user_data;
s3c2410_offset_t *reg;
int i;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
for (i = 0; i < usbdev->nr_regs; i++) {
reg = &usbdev->regs[i];
if (NULL == reg->name)
continue;
*(reg->datap) = reg->reset;
}
return 0;
}
static CPUReadMemoryFunc *s3c2410_usbdev_readfn[] =
{
s3c2410_usbdev_read,
s3c2410_usbdev_read,
s3c2410_usbdev_read
};
static CPUWriteMemoryFunc *s3c2410_usbdev_writefn[] =
{
s3c2410_usbdev_write,
s3c2410_usbdev_write,
s3c2410_usbdev_write
};
static int
s3c2410_usbdev_init(x49gp_module_t *module)
{
s3c2410_usbdev_t *usbdev;
int iotype;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
usbdev = malloc(sizeof(s3c2410_usbdev_t));
if (NULL == usbdev) {
fprintf(stderr, "%s:%u: Out of memory\n",
__FUNCTION__, __LINE__);
return -ENOMEM;
}
if (s3c2410_usbdev_data_init(usbdev)) {
free(usbdev);
return -ENOMEM;
}
module->user_data = usbdev;
#ifdef QEMU_OLD
iotype = cpu_register_io_memory(0, s3c2410_usbdev_readfn,
s3c2410_usbdev_writefn, usbdev);
#else
iotype = cpu_register_io_memory(s3c2410_usbdev_readfn,
s3c2410_usbdev_writefn, usbdev);
#endif
printf("%s: iotype %08x\n", __FUNCTION__, iotype);
cpu_register_physical_memory(S3C2410_USBDEV_BASE, S3C2410_MAP_SIZE, iotype);
return 0;
}
static int
s3c2410_usbdev_exit(x49gp_module_t *module)
{
s3c2410_usbdev_t *usbdev;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
if (module->user_data) {
usbdev = module->user_data;
if (usbdev->regs)
free(usbdev->regs);
free(usbdev);
}
x49gp_module_unregister(module);
free(module);
return 0;
}
int
x49gp_s3c2410_usbdev_init(x49gp_t *x49gp)
{
x49gp_module_t *module;
if (x49gp_module_init(x49gp, "s3c2410-usbdev",
s3c2410_usbdev_init,
s3c2410_usbdev_exit,
s3c2410_usbdev_reset,
s3c2410_usbdev_load,
s3c2410_usbdev_save,
NULL, &module)) {
return -1;
}
return x49gp_module_register(module);
}