Skip to content

Instantly share code, notes, and snippets.

@pamaury
Created July 12, 2013 11:56
Show Gist options
  • Save pamaury/5983923 to your computer and use it in GitHub Desktop.
Save pamaury/5983923 to your computer and use it in GitHub Desktop.
Incomplete work to merge driver into our codebase: use rockbox defines, drop usb_instance, use global config, partially implement target functions. Probably doesn't compile
diff --git a/firmware/target/arm/synopsysotg.c b/firmware/target/arm/synopsysotg.c
index 6fc620d..8d2d73e 100644
--- a/firmware/target/arm/synopsysotg.c
+++ b/firmware/target/arm/synopsysotg.c
@@ -1,8 +1,7 @@
-#include "global.h"
-#include "core/synopsysotg/synopsysotg.h"
-#include "protocol/usb/usb.h"
-#include "sys/time.h"
-#include "sys/util.h"
+#include "synopsysotg_regs.h"
+#include "synopsysotg.h"
+#include "usb.h"
+#include "usb_ch9.h"
#ifndef SYNOPSYSOTG_AHB_BURST_LEN
#define SYNOPSYSOTG_AHB_BURST_LEN 5
@@ -14,50 +13,86 @@
#define SYNOPSYSOTG_TURNAROUND 3
#endif
-static void synopsysotg_flush_in_endpoint(const struct usb_instance* instance, int ep)
+struct __attribute__((packed,aligned(4))) synopsysotg_config
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
- if (data->core->inep_regs[ep].diepctl.b.epena)
+ volatile struct synopsysotg_core_regs* core;
+ uint32_t phy_16bit : 1;
+ uint32_t phy_ulpi : 1;
+ uint32_t use_dma : 1;
+ uint32_t disable_double_buffering : 1;
+ uint32_t reserved0 : 4;
+ uint8_t reserved1;
+ uint16_t fifosize;
+ uint16_t txfifosize[16];
+};
+
+#ifdef IPOD_NANO2G
+struct synopsysotg_config g_config =
+{
+ .core = (struct synopsysotg_core_regs*)OTGBASE;
+ .phy_16bit = true;
+ .phy_ulpi = false;
+ .use_dma = true;
+ .disable_double_buffering = false;
+ .fifosize = 1024;
+ .txfifosize = { 0x100, 0x100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+};
+#elif SANSA_CLIPPLUS
+struct synopsysotg_config g_config =
+{
+ .core = (struct synopsysotg_core_regs*)OTGBASE;
+ .phy_16bit = true;
+ .phy_ulpi = false;
+ .use_dma = true;
+ .disable_double_buffering = false;
+ .fifosize = 512;
+ .txfifosize = { 0x100, 0x100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+};
+#else
+#error define synopsysotg config
+#endif
+
+static void synopsysotg_flush_in_endpoint(int ep)
+{
+ if (g_config.core->inep_regs[ep].diepctl.b.epena)
{
// Urgh, someone was still babbling on our IN pipe, and now we have some
// old crap in the FIFO. Disable the endpoint, to make sure nobody will
// fetch any more old crap while we're trying to get rid of it.
- synopsysotg_target_disable_irq(instance);
- data->core->inep_regs[ep].diepctl.b.snak = 1;
- while (!(data->core->inep_regs[ep].diepint.b.inepnakeff));
- data->core->inep_regs[ep].diepctl.b.epdis = 1;
- while (!(data->core->inep_regs[ep].diepint.b.epdisabled));
- synopsysotg_target_enable_irq(instance);
+ synopsysotg_target_disable_irq();
+ g_config.core->inep_regs[ep].diepctl.b.snak = 1;
+ while (!(g_config.core->inep_regs[ep].diepint.b.inepnakeff));
+ g_config.core->inep_regs[ep].diepctl.b.epdis = 1;
+ while (!(g_config.core->inep_regs[ep].diepint.b.epdisabled));
+ synopsysotg_target_enable_irq();
// Wait for any DMA activity to stop, to make sure nobody will touch the FIFO.
- while (!data->core->gregs.grstctl.b.ahbidle);
+ while (!g_config.core->gregs.grstctl.b.ahbidle);
// Flush it all the way down!
union synopsysotg_grstctl grstctl = { .b = { .txfnum = ep, .txfflsh = 1 } };
- data->core->gregs.grstctl = grstctl;
- while (data->core->gregs.grstctl.b.txfflsh);
+ g_config.core->gregs.grstctl = grstctl;
+ while (g_config.core->gregs.grstctl.b.txfflsh);
}
// Reset the transfer size register. Not strictly neccessary, but can't hurt.
- data->core->inep_regs[ep].dieptsiz.d32 = 0;
+ g_config.core->inep_regs[ep].dieptsiz.d32 = 0;
}
-static void synopsysotg_flush_ints(const struct usb_instance* instance)
+static void synopsysotg_flush_ints()
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
int i;
for (i = 0; i < 16; i++)
{
- data->core->outep_regs[i].doepint = data->core->outep_regs[i].doepint;
- data->core->inep_regs[i].diepint = data->core->inep_regs[i].diepint;
+ g_config.core->outep_regs[i].doepint = g_config.core->outep_regs[i].doepint;
+ g_config.core->inep_regs[i].diepint = g_config.core->inep_regs[i].diepint;
}
- data->core->gregs.gintsts = data->core->gregs.gintsts;
+ g_config.core->gregs.gintsts = g_config.core->gregs.gintsts;
}
-void synopsysotg_start_rx(const struct usb_instance* instance, union usb_endpoint_number ep, void* buf, int size)
+void synopsysotg_start_rx(union usb_endpoint_number ep, void* buf, int size)
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
- struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
+ struct synopsysotg_state* state = (struct synopsysotg_state*)->driver_state;
// Find the appropriate set of endpoint registers
- volatile struct synopsysotg_outepregs* regs = &data->core->outep_regs[ep.number];
+ volatile struct synopsysotg_outepregs* regs = &g_config.core->outep_regs[ep.number];
// Calculate number of packets (if size == 0 an empty packet will be sent)
int maxpacket = regs->doepctl.b.mps;
@@ -65,13 +100,13 @@ void synopsysotg_start_rx(const struct usb_instance* instance, union usb_endpoin
if (!packets) packets = 1;
// Set up data desination
- if (data->use_dma) regs->doepdma = buf;
+ if (g_config.use_dma) regs->doepdma = synopsysotg_target_get_phys_addr(buf);
else state->endpoints[ep.number].rxaddr = (uint32_t*)buf;
union synopsysotg_depxfrsiz deptsiz = { .b = { .pktcnt = packets, .xfersize = size } };
regs->doeptsiz = deptsiz;
// Flush CPU cache if necessary
- if (data->use_dma) invalidate_dcache(buf, size);
+ if (g_config.use_dma) synopsysotg_target_invalidate_dcache(buf, size);
// Enable the endpoint
union synopsysotg_depctl depctl = regs->doepctl;
@@ -80,13 +115,12 @@ void synopsysotg_start_rx(const struct usb_instance* instance, union usb_endpoin
regs->doepctl = depctl;
}
-void synopsysotg_start_tx(const struct usb_instance* instance, union usb_endpoint_number ep, const void* buf, int size)
+void synopsysotg_start_tx(union usb_endpoint_number ep, const void* buf, int size)
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
- struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
+ struct synopsysotg_state* state = (struct synopsysotg_state*)->driver_state;
// Find the appropriate set of endpoint registers
- volatile struct synopsysotg_inepregs* regs = &data->core->inep_regs[ep.number];
+ volatile struct synopsysotg_inepregs* regs = &g_config.core->inep_regs[ep.number];
// Calculate number of packets (if size == 0 an empty packet will be sent)
int maxpacket = regs->diepctl.b.mps;
@@ -94,13 +128,13 @@ void synopsysotg_start_tx(const struct usb_instance* instance, union usb_endpoin
if (!packets) packets = 1;
// Set up data desination
- if (data->use_dma) regs->diepdma = buf;
+ if (g_config.use_dma) regs->diepdma = synopsysotg_target_get_phys_addr(buf);
else state->endpoints[ep.number].txaddr = (uint32_t*)buf;
union synopsysotg_depxfrsiz deptsiz = { .b = { .pktcnt = packets, .xfersize = size } };
regs->dieptsiz = deptsiz;
// Flush CPU cache if necessary
- if (data->use_dma) clean_dcache(buf, size);
+ if (g_config.use_dma) synopsysotg_target_clean_dcache(buf, size);
// Enable the endpoint
union synopsysotg_depctl depctl = regs->diepctl;
@@ -109,329 +143,305 @@ void synopsysotg_start_tx(const struct usb_instance* instance, union usb_endpoin
regs->diepctl = depctl;
// Start pushing data into the FIFO (must be done after enabling the endpoint)
- if (!data->use_dma) data->core->dregs.diepempmsk.ep.in |= (1 << ep.number);
+ if (!g_config.use_dma) g_config.core->dregs.diepempmsk.ep.in |= (1 << ep.number);
}
-void synopsysotg_set_stall(const struct usb_instance* instance, union usb_endpoint_number ep, int stall)
+void synopsysotg_set_stall(union usb_endpoint_number ep, int stall)
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
- if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
- data->core->inep_regs[ep.number].diepctl.b.stall = !!stall;
- else data->core->outep_regs[ep.number].doepctl.b.stall = !!stall;
+ if (ep.direction == DIR_IN)
+ g_config.core->inep_regs[ep.number].diepctl.b.stall = !!stall;
+ else g_config.core->outep_regs[ep.number].doepctl.b.stall = !!stall;
}
-void synopsysotg_set_address(const struct usb_instance* instance, uint8_t address)
+void synopsysotg_set_address(uint8_t address)
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
- data->core->dregs.dcfg.b.devaddr = address;
+ g_config.core->dregs.dcfg.b.devaddr = address;
}
-void synopsysotg_unconfigure_ep(const struct usb_instance* instance, union usb_endpoint_number ep)
+void synopsysotg_unconfigure_ep(union usb_endpoint_number ep)
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
union synopsysotg_depctl depctl = { .b = { .epdis = 1 } };
- if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
+ if (ep.direction == DIR_IN)
{
- synopsysotg_flush_in_endpoint(instance, ep.number);
- data->core->inep_regs[ep.number].diepctl = depctl;
+ synopsysotg_flush_in_endpoint(ep.number);
+ g_config.core->inep_regs[ep.number].diepctl = depctl;
// Mask interrupts for this endpoint
- data->core->dregs.daintmsk.ep.in &= ~(1 << ep.number);
+ g_config.core->dregs.daintmsk.ep.in &= ~(1 << ep.number);
}
else
{
// We can't really do much about in-flight OUT requests except for ignoring them.
- data->core->outep_regs[ep.number].doeptsiz.d32 = 0;
- data->core->outep_regs[ep.number].doepctl = depctl;
+ g_config.core->outep_regs[ep.number].doeptsiz.d32 = 0;
+ g_config.core->outep_regs[ep.number].doepctl = depctl;
// Mask interrupts for this endpoint
- data->core->dregs.daintmsk.ep.out &= ~(1 << ep.number);
+ g_config.core->dregs.daintmsk.ep.out &= ~(1 << ep.number);
}
}
-void synopsysotg_configure_ep(const struct usb_instance* instance, union usb_endpoint_number ep,
+void synopsysotg_configure_ep(union usb_endpoint_number ep,
enum usb_endpoint_type type, int maxpacket)
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
// Reset the endpoint, just in case someone left it in a dirty state.
- synopsysotg_unconfigure_ep(instance, ep);
+ synopsysotg_unconfigure_ep(ep);
// Write the new configuration and unmask interrupts for the endpoint.
// Reset data toggle to DATA0, as required by the USB specification.
union synopsysotg_depctl depctl = { .b = { .usbactep = 1, .eptype = type, .mps = maxpacket, .txfnum = ep.number, .setd0pid = 1 } };
- if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
+ if (ep.direction == DIR_IN)
{
- data->core->inep_regs[ep.number].diepctl = depctl;
- data->core->dregs.daintmsk.ep.in |= (1 << ep.number);
+ g_config.core->inep_regs[ep.number].diepctl = depctl;
+ g_config.core->dregs.daintmsk.ep.in |= (1 << ep.number);
}
else
{
- data->core->outep_regs[ep.number].doepctl = depctl;
- data->core->dregs.daintmsk.ep.out |= (1 << ep.number);
+ g_config.core->outep_regs[ep.number].doepctl = depctl;
+ g_config.core->dregs.daintmsk.ep.out |= (1 << ep.number);
}
}
-void synopsysotg_ep0_start_rx(const struct usb_instance* instance, int non_setup)
+void synopsysotg_ep0_start_rx(int non_setup)
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
- struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
+ struct synopsysotg_state* state = (struct synopsysotg_state*)->driver_state;
// If we don't expect a non-SETUP packet, we can stall the OUT pipe,
// SETUP packets will ignore that.
- if (!non_setup) data->core->outep_regs[0].doepctl.b.stall = 1;
+ if (!non_setup) g_config.core->outep_regs[0].doepctl.b.stall = 1;
// Set up data desination
- if (data->use_dma) data->core->outep_regs[0].doepdma = instance->buffer;
- else state->endpoints[0].rxaddr = (uint32_t*)instance->buffer;
+ if (g_config.use_dma) g_config.core->outep_regs[0].doepdma = ->buffer;
+ else state->endpoints[0].rxaddr = (uint32_t*)->buffer;
union synopsysotg_dep0xfrsiz deptsiz = { .b = { .supcnt = 3, .pktcnt = !!non_setup, .xfersize = 64 } };
- data->core->outep_regs[0].doeptsiz.d32 = deptsiz.d32;
+ g_config.core->outep_regs[0].doeptsiz.d32 = deptsiz.d32;
// Flush CPU cache if necessary
- if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
+ if (g_config.use_dma) invalidate_dcache(->buffer, sizeof(->buffer));
// Enable the endpoint
- union synopsysotg_depctl depctl = data->core->outep_regs[0].doepctl;
+ union synopsysotg_depctl depctl = g_config.core->outep_regs[0].doepctl;
depctl.b.epena = 1;
depctl.b.cnak = 1;
- data->core->outep_regs[0].doepctl = depctl;
+ g_config.core->outep_regs[0].doepctl = depctl;
}
-void synopsysotg_ep0_start_tx(const struct usb_instance* instance, const void* buf, int len)
+void synopsysotg_ep0_start_tx(const void* buf, int len)
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
- struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
+ struct synopsysotg_state* state = (struct synopsysotg_state*)->driver_state;
if (len)
{
// Set up data source
- if (data->use_dma) data->core->inep_regs[0].diepdma = buf;
+ if (g_config.use_dma) g_config.core->inep_regs[0].diepdma = buf;
else state->endpoints[0].txaddr = buf;
union synopsysotg_dep0xfrsiz deptsiz = { .b = { .pktcnt = (len + 63) >> 6, .xfersize = len } };
- data->core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
+ g_config.core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
}
else
{
// Set up the IN pipe for a zero-length packet
union synopsysotg_dep0xfrsiz deptsiz = { .b = { .pktcnt = 1 } };
- data->core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
+ g_config.core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
}
// Flush CPU cache if necessary
- if (data->use_dma) clean_dcache(buf, len);
+ if (g_config.use_dma) clean_dcache(buf, len);
// Enable the endpoint
- union synopsysotg_depctl depctl = data->core->inep_regs[0].diepctl;
+ union synopsysotg_depctl depctl = g_config.core->inep_regs[0].diepctl;
depctl.b.epena = 1;
depctl.b.cnak = 1;
- data->core->inep_regs[0].diepctl = depctl;
+ g_config.core->inep_regs[0].diepctl = depctl;
// Start pushing data into the FIFO (must be done after enabling the endpoint)
- if (len && !data->use_dma) data->core->dregs.diepempmsk.ep.in |= 1;
+ if (len && !g_config.use_dma) g_config.core->dregs.diepempmsk.ep.in |= 1;
}
-static void synopsysotg_ep0_init(const struct usb_instance* instance)
+static void synopsysotg_ep0_init()
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
-
// Make sure both EP0 pipes are active.
// (The hardware should take care of that, but who knows...)
union synopsysotg_depctl depctl = { .b = { .usbactep = 1 } };
- data->core->outep_regs[0].doepctl = depctl;
- data->core->inep_regs[0].diepctl = depctl;
+ g_config.core->outep_regs[0].doepctl = depctl;
+ g_config.core->inep_regs[0].diepctl = depctl;
// Prime EP0 for the first setup packet.
- usb_ep0_expect_setup(instance);
+ usb_ep0_expect_setup();
}
-void synopsysotg_irq(const struct usb_instance* instance)
+void synopsysotg_irq()
{
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
- struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
+ struct synopsysotg_state* state = (struct synopsysotg_state*)->driver_state;
- union synopsysotg_gintsts gintsts = data->core->gregs.gintsts;
+ union synopsysotg_gintsts gintsts = g_config.core->gregs.gintsts;
if (gintsts.b.usbreset)
{
- data->core->dregs.dcfg.b.devaddr = 0;
- synopsysotg_ep0_init(instance);
- usb_handle_bus_reset(instance, data->core->dregs.dsts.b.enumspd == 0);
+ g_config.core->dregs.dcfg.b.devaddr = 0;
+ synopsysotg_ep0_init();
+ usb_handle_bus_reset(g_config.core->dregs.dsts.b.enumspd == 0);
}
if (gintsts.b.rxstsqlvl)
{
// Device to memory part of the "software DMA" implementation, used to receive data if use_dma == 0.
// Handle one packet at a time, the IRQ will re-trigger if there's something left.
- union synopsysotg_grxfsts rxsts = data->core->gregs.grxstsp;
+ union synopsysotg_grxfsts rxsts = g_config.core->gregs.grxstsp;
int ep = rxsts.b.chnum;
int words = (rxsts.b.bcnt + 3) >> 2;
- while (words--) *state->endpoints[ep].rxaddr++ = data->core->dfifo[0][0];
+ while (words--) *state->endpoints[ep].rxaddr++ = g_config.core->dfifo[0][0];
}
if (gintsts.b.inepintr)
{
- union synopsysotg_daint daint = data->core->dregs.daint;
+ union synopsysotg_daint daint = g_config.core->dregs.daint;
int ep;
for (ep = 0; ep < 16; ep++)
if (daint.ep.in & (1 << ep))
{
- union synopsysotg_diepintn epints = data->core->inep_regs[ep].diepint;
+ union synopsysotg_diepintn epints = g_config.core->inep_regs[ep].diepint;
if (epints.b.emptyintr)
{
// Memory to device part of the "software DMA" implementation, used to transmit data if use_dma == 0.
- union synopsysotg_depxfrsiz deptsiz = data->core->inep_regs[ep].dieptsiz;
- if (!deptsiz.b.pktcnt) data->core->dregs.diepempmsk.ep.in &= ~(1 << ep);
+ union synopsysotg_depxfrsiz deptsiz = g_config.core->inep_regs[ep].dieptsiz;
+ if (!deptsiz.b.pktcnt) g_config.core->dregs.diepempmsk.ep.in &= ~(1 << ep);
else
{
// Push data into the TX FIFO until we don't have anything left or the FIFO would overflow.
int left = (deptsiz.b.xfersize + 3) >> 2;
while (left)
{
- int words = data->core->inep_regs[ep].dtxfsts.b.txfspcavail;
+ int words = g_config.core->inep_regs[ep].dtxfsts.b.txfspcavail;
if (words > left) words = left;
if (!words) break;
left -= words;
- while (words--) data->core->dfifo[ep][0] = *state->endpoints[ep].txaddr++;
+ while (words--) g_config.core->dfifo[ep][0] = *state->endpoints[ep].txaddr++;
}
}
}
- union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_IN, .number = ep };
- int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
- if (epints.b.timeout) usb_handle_timeout(instance, epnum, bytesleft);
- if (epints.b.xfercompl) usb_handle_xfer_complete(instance, epnum, bytesleft);
- data->core->inep_regs[ep].diepint = epints;
+ union usb_endpoint_number epnum = { .direction = DIR_IN, .number = ep };
+ int bytesleft = g_config.core->inep_regs[ep].dieptsiz.b.xfersize;
+ if (epints.b.timeout) usb_handle_timeout(epnum, bytesleft);
+ if (epints.b.xfercompl) usb_handle_xfer_complete(epnum, bytesleft);
+ g_config.core->inep_regs[ep].diepint = epints;
}
}
if (gintsts.b.outepintr)
{
- union synopsysotg_daint daint = data->core->dregs.daint;
+ union synopsysotg_daint daint = g_config.core->dregs.daint;
int ep;
for (ep = 0; ep < 16; ep++)
if (daint.ep.out & (1 << ep))
{
- union synopsysotg_doepintn epints = data->core->outep_regs[ep].doepint;
- union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_OUT, .number = ep };
+ union synopsysotg_doepintn epints = g_config.core->outep_regs[ep].doepint;
+ union usb_endpoint_number epnum = { .direction = DIR_OUT, .number = ep };
if (epints.b.setup)
{
- if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
- union synopsysotg_dep0xfrsiz deptsiz = { .d32 = data->core->outep_regs[0].doeptsiz.d32 };
+ if (g_config.use_dma) invalidate_dcache(->buffer, sizeof(->buffer));
+ union synopsysotg_dep0xfrsiz deptsiz = { .d32 = g_config.core->outep_regs[0].doeptsiz.d32 };
int back2back = 3 - deptsiz.b.supcnt;
- synopsysotg_flush_in_endpoint(instance, ep);
- usb_handle_setup_received(instance, epnum, back2back);
+ synopsysotg_flush_in_endpoint(ep);
+ usb_handle_setup_received(epnum, back2back);
}
else if (epints.b.xfercompl)
{
- int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
- usb_handle_xfer_complete(instance, epnum, bytesleft);
+ int bytesleft = g_config.core->inep_regs[ep].dieptsiz.b.xfersize;
+ usb_handle_xfer_complete(epnum, bytesleft);
}
- data->core->outep_regs[ep].doepint = epints;
+ g_config.core->outep_regs[ep].doepint = epints;
}
}
- data->core->gregs.gintsts = gintsts;
+ g_config.core->gregs.gintsts = gintsts;
}
-void synopsysotg_init(const struct usb_instance* instance)
+void synopsysotg_init()
{
int i;
- const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
-
// Disable IRQ during setup
- synopsysotg_target_disable_irq(instance);
+ synopsysotg_target_disable_irq();
// Enable OTG clocks
- synopsysotg_target_enable_clocks(instance);
+ synopsysotg_target_enable_clocks();
// Enable PHY clocks
union synopsysotg_pcgcctl pcgcctl = { .b = {} };
- data->core->pcgcctl = pcgcctl;
+ g_config.core->pcgcctl = pcgcctl;
// Configure PHY type (must be done before reset)
union synopsysotg_gccfg gccfg = { .b = { .disablevbussensing = 1, .pwdn = 0 } };
- data->core->gregs.gccfg = gccfg;
+ g_config.core->gregs.gccfg = gccfg;
union synopsysotg_gusbcfg gusbcfg = { .b = { .force_dev = 1, .usbtrdtim = SYNOPSYSOTG_TURNAROUND } };
- if (data->phy_16bit) gusbcfg.b.phyif = 1;
- else if (data->phy_ulpi) gusbcfg.b.ulpi_utmi_sel = 1;
+ if (g_config.phy_16bit) gusbcfg.b.phyif = 1;
+ else if (g_config.phy_ulpi) gusbcfg.b.ulpi_utmi_sel = 1;
else gusbcfg.b.physel = 1;
- data->core->gregs.gusbcfg = gusbcfg;
+ g_config.core->gregs.gusbcfg = gusbcfg;
// Reset the whole USB core
union synopsysotg_grstctl grstctl = { .b = { .csftrst = 1 } };
udelay(100);
- while (!data->core->gregs.grstctl.b.ahbidle);
- data->core->gregs.grstctl = grstctl;
- while (data->core->gregs.grstctl.b.csftrst);
- while (!data->core->gregs.grstctl.b.ahbidle);
+ while (!g_config.core->gregs.grstctl.b.ahbidle);
+ g_config.core->gregs.grstctl = grstctl;
+ while (g_config.core->gregs.grstctl.b.csftrst);
+ while (!g_config.core->gregs.grstctl.b.ahbidle);
// Soft disconnect
union synopsysotg_dctl dctl = { .b = { .sftdiscon = 1 } };
- data->core->dregs.dctl = dctl;
+ g_config.core->dregs.dctl = dctl;
// Configure the core
- union synopsysotg_gahbcfg gahbcfg = { .b = { .dmaenable = data->use_dma, .hburstlen = SYNOPSYSOTG_AHB_BURST_LEN, .glblintrmsk = 1 } };
- if (data->disable_double_buffering)
+ union synopsysotg_gahbcfg gahbcfg = { .b = { .dmaenable = g_config.use_dma, .hburstlen = SYNOPSYSOTG_AHB_BURST_LEN, .glblintrmsk = 1 } };
+ if (g_config.disable_double_buffering)
{
gahbcfg.b.nptxfemplvl_txfemplvl = 1;
gahbcfg.b.ptxfemplvl = 1;
}
- data->core->gregs.gahbcfg = gahbcfg;
- data->core->gregs.gusbcfg = gusbcfg;
+ g_config.core->gregs.gahbcfg = gahbcfg;
+ g_config.core->gregs.gusbcfg = gusbcfg;
gccfg.b.pwdn = 1;
- data->core->gregs.gccfg = gccfg;
+ g_config.core->gregs.gccfg = gccfg;
union synopsysotg_dcfg dcfg = { .b = { .nzstsouthshk = 1 } };
- data->core->dregs.dcfg = dcfg;
+ g_config.core->dregs.dcfg = dcfg;
// Configure the FIFOs
- if (data->use_dma)
+ if (g_config.use_dma)
{
union synopsysotg_dthrctl dthrctl = { .b = { .arb_park_en = 1, .rx_thr_en = 1, .iso_thr_en = 0, .non_iso_thr_en = 0,
.rx_thr_len = SYNOPSYSOTG_AHB_THRESHOLD } };
- data->core->dregs.dthrctl = dthrctl;
+ g_config.core->dregs.dthrctl = dthrctl;
}
- int addr = data->fifosize;
+ int addr = g_config.fifosize;
for (i = 0; i < 16; i++)
{
- int size = data->txfifosize[i];
+ int size = g_config.txfifosize[i];
addr -= size;
if (size)
{
union synopsysotg_txfsiz fsiz = { .b = { .startaddr = addr, .depth = size } };
- if (!i) data->core->gregs.dieptxf0_hnptxfsiz = fsiz;
- else data->core->gregs.dieptxf[i - 1] = fsiz;
+ if (!i) g_config.core->gregs.dieptxf0_hnptxfsiz = fsiz;
+ else g_config.core->gregs.dieptxf[i - 1] = fsiz;
}
}
union synopsysotg_rxfsiz fsiz = { .b = { .depth = addr } };
- data->core->gregs.grxfsiz = fsiz;
+ g_config.core->gregs.grxfsiz = fsiz;
// Set up interrupts
union synopsysotg_doepintn doepmsk = { .b = { .xfercompl = 1, .setup = 1 } };
- data->core->dregs.doepmsk = doepmsk;
+ g_config.core->dregs.doepmsk = doepmsk;
union synopsysotg_diepintn diepmsk = { .b = { .xfercompl = 1, .timeout = 1 } };
- data->core->dregs.diepmsk = diepmsk;
- data->core->dregs.diepempmsk.d32 = 0;
+ g_config.core->dregs.diepmsk = diepmsk;
+ g_config.core->dregs.diepempmsk.d32 = 0;
union synopsysotg_daint daintmsk = { .ep = { .in = 0b0000000000000001, .out = 0b0000000000000001 } };
- data->core->dregs.daintmsk = daintmsk;
+ g_config.core->dregs.daintmsk = daintmsk;
union synopsysotg_gintmsk gintmsk = { .b = { .usbreset = 1, .outepintr = 1, .inepintr = 1 } };
- if (!data->use_dma) gintmsk.b.rxstsqlvl = 1;
- data->core->gregs.gintmsk = gintmsk;
- synopsysotg_flush_ints(instance);
- synopsysotg_target_clear_irq(instance);
- synopsysotg_target_enable_irq(instance);
+ if (!g_config.use_dma) gintmsk.b.rxstsqlvl = 1;
+ g_config.core->gregs.gintmsk = gintmsk;
+ synopsysotg_flush_ints();
+ synopsysotg_target_clear_irq();
+ synopsysotg_target_enable_irq();
// Soft reconnect
dctl.b.sftdiscon = 0;
- data->core->dregs.dctl = dctl;
+ g_config.core->dregs.dctl = dctl;
}
-
-const struct usb_driver synopsysotg_driver =
-{
- .init = synopsysotg_init,
- .ep0_start_rx = synopsysotg_ep0_start_rx,
- .ep0_start_tx = synopsysotg_ep0_start_tx,
- .start_rx = synopsysotg_start_rx,
- .start_tx = synopsysotg_start_tx,
- .set_stall = synopsysotg_set_stall,
- .set_address = synopsysotg_set_address,
- .configure_ep = synopsysotg_configure_ep,
- .unconfigure_ep = synopsysotg_unconfigure_ep,
-};
diff --git a/firmware/target/arm/synopsysotg.h b/firmware/target/arm/synopsysotg.h
index a335115..bce99e5 100644
--- a/firmware/target/arm/synopsysotg.h
+++ b/firmware/target/arm/synopsysotg.h
@@ -1,22 +1,8 @@
#ifndef __CORE_SYNOPSYSOTG_SYNOPSYSOTG_H__
#define __CORE_SYNOPSYSOTG_SYNOPSYSOTG_H__
-#include "global.h"
-#include "protocol/usb/usb.h"
-#include "core/synopsysotg/regs.h"
-
-struct __attribute__((packed,aligned(4))) synopsysotg_config
-{
- volatile struct synopsysotg_core_regs* core;
- uint32_t phy_16bit : 1;
- uint32_t phy_ulpi : 1;
- uint32_t use_dma : 1;
- uint32_t disable_double_buffering : 1;
- uint32_t reserved0 : 4;
- uint8_t reserved1;
- uint16_t fifosize;
- uint16_t txfifosize[16];
-};
+#include "usb.h"
+#include "usb_ch9.h"
struct __attribute__((packed,aligned(4))) synopsysotg_state
{
@@ -28,12 +14,34 @@ struct __attribute__((packed,aligned(4))) synopsysotg_state
} endpoints[];
};
-extern const struct usb_driver synopsysotg_driver;
+union __attribute__((packed)) usb_endpoint_number
+{
+ struct __attribute__((packed))
+ {
+ int number : 4;
+ int reserved: 3;
+ int direction : 1;
+ };
+ uint8_t byte;
+};
+
+void synopsysotg_init();
+void synopsysotg_ep0_start_rx(int non_setup);
+void synopsysotg_ep0_start_tx(const void* buf, int len);
+void synopsysotg_start_rx(union usb_endpoint_number ep, void* buf, int size);
+void synopsysotg_start_tx(union usb_endpoint_number ep, const void* buf, int size);
+void synopsysotg_set_stall(union usb_endpoint_number ep, int stall);
+void synopsysotg_set_address(uint8_t address);
+void synopsysotg_configure_ep(union usb_endpoint_number ep, enum usb_endpoint_type type, int maxpacket);
+void synopsysotg_unconfigure_ep(union usb_endpoint_number ep);
+void synopsysotg_irq();
-extern void synopsysotg_irq(const struct usb_instance* instance);
-extern void synopsysotg_target_enable_clocks(const struct usb_instance* instance);
-extern void synopsysotg_target_enable_irq(const struct usb_instance* instance);
-extern void synopsysotg_target_disable_irq(const struct usb_instance* instance);
-extern void synopsysotg_target_clear_irq(const struct usb_instance* instance);
+void synopsysotg_target_enable_clocks();
+void synopsysotg_target_enable_irq();
+void synopsysotg_target_disable_irq();
+void synopsysotg_target_clear_irq();
+void synopsysotg_target_clean_dcache(const void *buf, int len);
+void synopsysotg_target_invalidate_dcache(const void *buf, int len);
+uint32_t synopsysotg_target_get_phys_addr(const void *buf);
#endif
diff --git a/firmware/target/arm/usb-s3c6400x.c b/firmware/target/arm/usb-s3c6400x.c
index 48521aa..d39e7be 100644
--- a/firmware/target/arm/usb-s3c6400x.c
+++ b/firmware/target/arm/usb-s3c6400x.c
@@ -40,229 +40,84 @@
#include "logf.h"
#if CONFIG_CPU == AS3525v2
-#define UNCACHED_ADDR AS3525_UNCACHED_ADDR
-#define PHYSICAL_ADDR AS3525_PHYSICAL_ADDR
-static inline void discard_dma_buffer_cache(void) {}
-#else
-#define UNCACHED_ADDR
-#define PHYSICAL_ADDR
-static inline void discard_dma_buffer_cache(void) { commit_discard_dcache(); }
-#endif
-
-/* store per endpoint, per direction, information */
-struct ep_type
-{
- unsigned int size; /* length of the data buffer */
- struct semaphore complete; /* wait object */
- int8_t status; /* completion status (0 for success) */
- bool active; /* true is endpoint has been requested (true for EP0) */
- bool done; /* transfer completed */
- bool busy; /* true is a transfer is pending */
-};
-
-static const uint8_t in_ep_list[] = {0, 1, 3, 5};
-static const uint8_t out_ep_list[] = {0, 2, 4};
-
-/* state of EP0 (to correctly schedule setup packet enqueing) */
-enum ep0state
+void synopsysotg_target_clean_dcache(const void *buf, int len)
{
- /* Setup packet is enqueud, waiting for actual data */
- EP0_WAIT_SETUP = 0,
- /* Waiting for ack (either IN or OUT) */
- EP0_WAIT_ACK = 1,
- /* Ack complete, waiting for data (either IN or OUT)
- * This state is necessary because if both ack and data complete in the
- * same interrupt, we might process data completion before ack completion
- * so we need this bizarre state */
- EP0_WAIT_DATA = 2,
- /* Setup packet complete, waiting for ack and data */
- EP0_WAIT_DATA_ACK = 3,
-};
-
-/* endpoints[ep_num][DIR_IN/DIR_OUT] */
-static struct ep_type endpoints[USB_NUM_ENDPOINTS][2];
-/* setup packet for EP0 */
-
-/* USB control requests may be up to 64 bytes in size.
- Even though we never use anything more than the 8 header bytes,
- we are required to accept request packets of up to 64 bytes size.
- Provide buffer space for these additional payload bytes so that
- e.g. write descriptor requests (which are rejected by us, but the
- payload is transferred anyway) do not cause memory corruption.
- Fixes FS#12310. -- Michael Sparmann (theseven) */
-static union {
- struct usb_ctrlrequest header; /* 8 bytes */
- unsigned char payload[64];
-} _ep0_setup_pkt USB_DEVBSS_ATTR;
-
-static struct usb_ctrlrequest *ep0_setup_pkt = UNCACHED_ADDR(&_ep0_setup_pkt.header);
-
-/* state of EP0 */
-static enum ep0state ep0_state;
+ commit_dcache_range(buf, len);
+}
-bool usb_drv_stalled(int endpoint, bool in)
+void synopsysotg_target_invalidate_dcache(const void *buf, int len)
{
- return DEPCTL(endpoint, !in) & DEPCTL_stall;
+ discard_dcache_range(buf, len);
}
-void usb_drv_stall(int endpoint, bool stall, bool in)
+uint32_t synopsysotg_target_get_phys_addr(const void *buf)
{
- if (stall)
- DEPCTL(endpoint, !in) |= DEPCTL_stall;
- else
- DEPCTL(endpoint, !in) &= ~DEPCTL_stall;
+ return AS3525_PHYSICAL_ADDR(buf);
}
-
-void usb_drv_set_address(int address)
+#else
+void synopsysotg_target_clean_dcache(const void *buf, int len)
{
- (void)address;
- /* Ignored intentionally, because the controller requires us to set the
- new address before sending the response for some reason. So we'll
- already set it when the control request arrives, before passing that
- into the USB core, which will then call this dummy function. */
}
-static void ep_transfer(int ep, void *ptr, int len, bool out)
+void synopsysotg_target_invalidate_dcache(const void *buf, int len)
{
- /* disable interrupts to avoid any race */
- int oldlevel = disable_irq_save();
-
- struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
- endpoint->busy = true;
- endpoint->size = len;
- endpoint->status = -1;
-
- if (out)
- DEPCTL(ep, out) &= ~DEPCTL_stall;
-
- int mps = usb_drv_port_speed() ? 512 : 64;
- int nb_packets = (len + mps - 1) / mps;
- if (nb_packets == 0)
- nb_packets = 1;
-
- DEPDMA(ep, out) = len ? (void*)PHYSICAL_ADDR(ptr) : NULL;
- DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
- if(out)
- discard_dcache_range(ptr, len);
- else
- commit_dcache_range(ptr, len);
-
- logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out));
-
-// if (!out) while (((GNPTXSTS & 0xffff) << 2) < MIN(mps, length));
-
- DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak;
-
- restore_irq(oldlevel);
}
-int usb_drv_send_nonblocking(int endpoint, void *ptr, int length)
+uint32_t synopsysotg_target_get_phys_addr(const void *buf)
{
- ep_transfer(EP_NUM(endpoint), ptr, length, false);
- return 0;
+ return (uint32_t)buf;
}
+#endif
-int usb_drv_recv(int endpoint, void* ptr, int length)
+void synopsysotg_target_enable_clocks()
{
- ep_transfer(EP_NUM(endpoint), ptr, length, true);
- return 0;
}
-int usb_drv_port_speed(void)
+void synopsysotg_target_enable_irq()
{
- static const uint8_t speed[4] = {
- [DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ] = 1,
- [DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ] = 0,
- [DSTS_ENUMSPD_FS_PHY_48MHZ] = 0,
- [DSTS_ENUMSPD_LS_PHY_6MHZ] = 0,
- };
-
- unsigned enumspd = extract(DSTS, enumspd);
-
- if(enumspd == DSTS_ENUMSPD_LS_PHY_6MHZ)
- panicf("usb-drv: LS is not supported");
-
- return speed[enumspd & 3];
}
-void usb_drv_set_test_mode(int mode)
+void synopsysotg_target_disable_irq()
{
- /* there is a perfect matching between usb test mode code
- * and the register field value */
- DCTL = (DCTL & ~bitm(DCTL, tstctl)) | (mode << DCTL_tstctl_bitp);
}
-void usb_attach(void)
+void synopsysotg_target_clear_irq()
{
- usb_enable(true); // s5l only ?
- /* Nothing to do */
}
-static void prepare_setup_ep0(void)
+bool usb_drv_stalled(int endpoint, bool in)
{
- DEPDMA(0, true) = (void*)PHYSICAL_ADDR(&_ep0_setup_pkt);
- DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp)
- | (1 << DEPTSIZ0_pkcnt_bitp)
- | 8;
- DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak;
+}
- ep0_state = EP0_WAIT_SETUP;
+void usb_drv_stall(int endpoint, bool stall, bool in)
+{
}
-static size_t num_eps(bool out)
+void usb_drv_set_address(int address)
{
- return out ? sizeof(out_ep_list) : sizeof(in_ep_list);
}
-static void reset_endpoints(void)
+int usb_drv_send_nonblocking(int endpoint, void *ptr, int length)
{
- for (int dir = 0; dir < 2; dir++)
- {
- bool out = dir == DIR_OUT;
- for (unsigned i = 0; i < num_eps(dir == DIR_OUT); i++)
- {
- int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
- struct ep_type *endpoint = &endpoints[ep][out];
- endpoint->active = false;
- endpoint->busy = false;
- endpoint->status = -1;
- endpoint->done = true;
- semaphore_release(&endpoint->complete);
+}
- if (i != 0)
- DEPCTL(ep, out) = DEPCTL_setd0pid;
- }
- DEPCTL(0, out) = /*(DEPCTL_MPS_64 << DEPCTL_mps_bitp) | */ DEPCTL_usbactep;
- }
+int usb_drv_recv(int endpoint, void* ptr, int length)
+{
+}
- /* Setup next chain for IN eps */
- for (unsigned i = 0; i < num_eps(false); i++)
- {
- int ep = in_ep_list[i];
- int next_ep = in_ep_list[(i + 1) % num_eps(false)];
- DEPCTL(ep, false) |= next_ep << DEPCTL_nextep_bitp;
- }
+int usb_drv_port_speed(void)
+{
- prepare_setup_ep0();
}
-static void cancel_all_transfers(bool cancel_ep0)
+void usb_drv_set_test_mode(int mode)
{
- int flags = disable_irq_save();
-
- for (int dir = 0; dir < 2; dir++)
- for (unsigned i = !!cancel_ep0; i < num_eps(dir == DIR_OUT); i++)
- {
- int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
- struct ep_type *endpoint = &endpoints[ep][dir == DIR_OUT];
- endpoint->status = -1;
- endpoint->busy = false;
- endpoint->done = false;
- semaphore_release(&endpoint->complete);
- DEPCTL(ep, dir) = (DEPCTL(ep, dir) & ~DEPCTL_usbactep);
- }
+}
- restore_irq(flags);
+void usb_attach(void)
+{
+ usb_enable(true); // s5l only ?
+ /* Nothing to do */
}
#if CONFIG_CPU == AS3525v2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment