* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu-common.h"
#include "qemu-timer.h"
#include "usb.h"
#include "omap.h"
#include "irq.h"
+#include "devices.h"
+#include "sysbus.h"
-struct tusb_s {
- int iomemtype[2];
+typedef struct TUSBState {
+ SysBusDevice busdev;
+ MemoryRegion iomem[2];
qemu_irq irq;
- struct musb_s *musb;
+ MUSBState *musb;
QEMUTimer *otg_timer;
QEMUTimer *pwr_timer;
uint32_t pullup[2];
uint32_t control_config;
uint32_t otg_timer_val;
-};
+} TUSBState;
#define TUSB_DEVCLOCK 60000000 /* 60 MHz */
#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff)
#define TUSB_PROD_TEST_RESET_VAL 0xa596
-int tusb6010_sync_io(struct tusb_s *s)
-{
- return s->iomemtype[0];
-}
-
-int tusb6010_async_io(struct tusb_s *s)
-{
- return s->iomemtype[1];
-}
-
-static void tusb_intr_update(struct tusb_s *s)
+static void tusb_intr_update(TUSBState *s)
{
if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
}
-static void tusb_usbip_intr_update(struct tusb_s *s)
+static void tusb_usbip_intr_update(TUSBState *s)
{
/* TX interrupt in the MUSB */
if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
tusb_intr_update(s);
}
-static void tusb_dma_intr_update(struct tusb_s *s)
+static void tusb_dma_intr_update(TUSBState *s)
{
if (s->dma_intr & ~s->dma_mask)
s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
tusb_intr_update(s);
}
-static void tusb_gpio_intr_update(struct tusb_s *s)
+static void tusb_gpio_intr_update(TUSBState *s)
{
/* TODO: How is this signalled? */
}
-extern CPUReadMemoryFunc *musb_read[];
-extern CPUWriteMemoryFunc *musb_write[];
+extern CPUReadMemoryFunc * const musb_read[];
+extern CPUWriteMemoryFunc * const musb_write[];
static uint32_t tusb_async_readb(void *opaque, target_phys_addr_t addr)
{
- struct tusb_s *s = (struct tusb_s *) opaque;
+ TUSBState *s = (TUSBState *) opaque;
switch (addr & 0xfff) {
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
static uint32_t tusb_async_readh(void *opaque, target_phys_addr_t addr)
{
- struct tusb_s *s = (struct tusb_s *) opaque;
+ TUSBState *s = (TUSBState *) opaque;
switch (addr & 0xfff) {
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
static uint32_t tusb_async_readw(void *opaque, target_phys_addr_t addr)
{
- struct tusb_s *s = (struct tusb_s *) opaque;
+ TUSBState *s = (TUSBState *) opaque;
int offset = addr & 0xfff;
int epnum;
uint32_t ret;
return s->rx_config[epnum];
case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
(TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- epnum = (offset - TUSB_EP_MAX_PACKET_SIZE_OFFSET) >> 2;
return 0x00000000; /* TODO */
case TUSB_WAIT_COUNT:
return 0x00; /* TODO */
static void tusb_async_writeb(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- struct tusb_s *s = (struct tusb_s *) opaque;
+ TUSBState *s = (TUSBState *) opaque;
switch (addr & 0xfff) {
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
static void tusb_async_writeh(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- struct tusb_s *s = (struct tusb_s *) opaque;
+ TUSBState *s = (TUSBState *) opaque;
switch (addr & 0xfff) {
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
static void tusb_async_writew(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- struct tusb_s *s = (struct tusb_s *) opaque;
+ TUSBState *s = (TUSBState *) opaque;
int offset = addr & 0xfff;
int epnum;
s->dev_config = value;
s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
- cpu_abort(cpu_single_env, "%s: Product Test mode not allowed\n",
- __FUNCTION__);
+ hw_error("%s: Product Test mode not allowed\n", __FUNCTION__);
break;
case TUSB_PHY_OTG_CTRL_ENABLE:
case TUSB_DEV_OTG_TIMER:
s->otg_timer_val = value;
if (value & TUSB_DEV_OTG_TIMER_ENABLE)
- qemu_mod_timer(s->otg_timer, qemu_get_clock(vm_clock) +
+ qemu_mod_timer(s->otg_timer, qemu_get_clock_ns(vm_clock) +
muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
- ticks_per_sec, TUSB_DEVCLOCK));
+ get_ticks_per_sec(), TUSB_DEVCLOCK));
else
qemu_del_timer(s->otg_timer);
break;
break;
case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
(TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- epnum = (offset - TUSB_EP_MAX_PACKET_SIZE_OFFSET) >> 2;
return; /* TODO */
case TUSB_WAIT_COUNT:
return; /* TODO */
}
}
-static CPUReadMemoryFunc *tusb_async_readfn[] = {
- tusb_async_readb,
- tusb_async_readh,
- tusb_async_readw,
-};
-
-static CPUWriteMemoryFunc *tusb_async_writefn[] = {
- tusb_async_writeb,
- tusb_async_writeh,
- tusb_async_writew,
+static const MemoryRegionOps tusb_async_ops = {
+ .old_mmio = {
+ .read = { tusb_async_readb, tusb_async_readh, tusb_async_readw, },
+ .write = { tusb_async_writeb, tusb_async_writeh, tusb_async_writew, },
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
static void tusb_otg_tick(void *opaque)
{
- struct tusb_s *s = (struct tusb_s *) opaque;
+ TUSBState *s = (TUSBState *) opaque;
s->otg_timer_val = 0;
s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
static void tusb_power_tick(void *opaque)
{
- struct tusb_s *s = (struct tusb_s *) opaque;
+ TUSBState *s = (TUSBState *) opaque;
if (s->power) {
s->intr_ok = ~0;
static void tusb_musb_core_intr(void *opaque, int source, int level)
{
- struct tusb_s *s = (struct tusb_s *) opaque;
+ TUSBState *s = (TUSBState *) opaque;
uint16_t otg_status = s->otg_status;
switch (source) {
}
}
-struct tusb_s *tusb6010_init(qemu_irq intr)
+static void tusb6010_power(TUSBState *s, int on)
{
- struct tusb_s *s = qemu_mallocz(sizeof(*s));
+ if (!on) {
+ s->power = 0;
+ } else if (!s->power && on) {
+ s->power = 1;
+ /* Pull the interrupt down after TUSB6010 comes up. */
+ s->intr_ok = 0;
+ tusb_intr_update(s);
+ qemu_mod_timer(s->pwr_timer,
+ qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 2);
+ }
+}
+
+static void tusb6010_irq(void *opaque, int source, int level)
+{
+ if (source) {
+ tusb_musb_core_intr(opaque, source - 1, level);
+ } else {
+ tusb6010_power(opaque, level);
+ }
+}
+
+static void tusb6010_reset(DeviceState *dev)
+{
+ TUSBState *s = FROM_SYSBUS(TUSBState, sysbus_from_qdev(dev));
+ int i;
s->test_reset = TUSB_PROD_TEST_RESET_VAL;
s->host_mode = 0;
s->mask = 0xffffffff;
s->intr = 0x00000000;
s->otg_timer_val = 0;
- s->iomemtype[1] = cpu_register_io_memory(0, tusb_async_readfn,
- tusb_async_writefn, s);
- s->irq = intr;
- s->otg_timer = qemu_new_timer(vm_clock, tusb_otg_tick, s);
- s->pwr_timer = qemu_new_timer(vm_clock, tusb_power_tick, s);
- s->musb = musb_init(qemu_allocate_irqs(tusb_musb_core_intr, s,
- __musb_irq_max));
-
- return s;
+ s->scratch = 0;
+ s->prcm_config = 0;
+ s->prcm_mngmt = 0;
+ s->intr_ok = 0;
+ s->usbip_intr = 0;
+ s->usbip_mask = 0;
+ s->gpio_intr = 0;
+ s->gpio_mask = 0;
+ s->gpio_config = 0;
+ s->dma_intr = 0;
+ s->dma_mask = 0;
+ s->dma_map = 0;
+ s->dma_config = 0;
+ s->ep0_config = 0;
+ s->wkup_mask = 0;
+ s->pullup[0] = s->pullup[1] = 0;
+ s->control_config = 0;
+ for (i = 0; i < 15; i++) {
+ s->rx_config[i] = s->tx_config[i] = 0;
+ }
+ musb_reset(s->musb);
}
-void tusb6010_power(struct tusb_s *s, int on)
+static int tusb6010_init(SysBusDevice *dev)
{
- if (!on)
- s->power = 0;
- else if (!s->power && on) {
- s->power = 1;
+ TUSBState *s = FROM_SYSBUS(TUSBState, dev);
+ s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s);
+ s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s);
+ memory_region_init_io(&s->iomem[1], &tusb_async_ops, s, "tusb-async",
+ UINT32_MAX);
+ sysbus_init_mmio(dev, &s->iomem[0]);
+ sysbus_init_mmio(dev, &s->iomem[1]);
+ sysbus_init_irq(dev, &s->irq);
+ qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1);
+ s->musb = musb_init(&dev->qdev, 1);
+ return 0;
+}
- /* Pull the interrupt down after TUSB6010 comes up. */
- s->intr_ok = 0;
- tusb_intr_update(s);
- qemu_mod_timer(s->pwr_timer,
- qemu_get_clock(vm_clock) + ticks_per_sec / 2);
- }
+static SysBusDeviceInfo tusb6010_info = {
+ .init = tusb6010_init,
+ .qdev.name = "tusb6010",
+ .qdev.size = sizeof(TUSBState),
+ .qdev.reset = tusb6010_reset,
+};
+
+static void tusb6010_register_device(void)
+{
+ sysbus_register_withprop(&tusb6010_info);
}
+
+device_init(tusb6010_register_device)