[U-Boot] [PATCH 2/2] pxa25x: Add USB ethernet gadget driver
Marek Vasut
marex at denx.de
Sun Aug 19 05:22:55 CEST 2012
Dear Łukasz Dałek,
[...]
The following comment still doesn't seem right.
> +/*
> --------------------------------------------------------------------------
> - + * endpoint related parts of the api to the usb controller hardware, +
> * used by gadget driver; and the inner talker-to-hardware core.
> + *
> --------------------------------------------------------------------------
> - + */
[...]
> +
> +/*
> + * when a driver is successfully registered, it will receive
> + * control requests including set_configuration(), which enables
> + * non-control requests. then usb traffic follows until a
> + * disconnect is reported. then a host may connect again, or
> + * the driver might get unbound.
> + */
> +int usb_gadget_register_driver(struct usb_gadget_driver *driver)
> +{
All this should certainly go into arch/arm/cpu/pxa/ ... as something like
"get_cpu_revision" or such ... don't you think? Then it can be used elsewhere
too if needed, give it some thought ;-)
> + struct pxa25x_udc *dev = &memory;
> + int retval;
> + uint32_t chiprev;
> +
> + if (!driver
> + || driver->speed < USB_SPEED_FULL
> + || !driver->disconnect
> + || !driver->setup)
> + return -EINVAL;
> + if (!dev)
> + return -ENODEV;
> + if (dev->driver)
> + return -EBUSY;
> +
> + /* Enable clock for usb controller */
> + setbits_le32(CKEN, CKEN11_USB);
> +
> + /* first hook up the driver ... */
> + dev->driver = driver;
> + dev->pullup = 1;
> +
> + /* insist on Intel/ARM/XScale */
> + asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));
> + if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {
> + printf("%s: not XScale!\n", DRIVER_NAME);
> + return -ENODEV;
> + }
> +
> + /* trigger chiprev-specific logic */
> + switch (chiprev & CP15R0_PRODREV_MASK) {
> + case PXA255_A0:
> + dev->has_cfr = 1;
> + break;
> + case PXA250_A0:
> + case PXA250_A1:
> + /* A0/A1 "not released"; ep 13, 15 unusable */
> + /* fall through */
> + case PXA250_B2: case PXA210_B2:
> + case PXA250_B1: case PXA210_B1:
> + case PXA250_B0: case PXA210_B0:
> + /* OUT-DMA is broken ... */
> + /* fall through */
> + case PXA250_C0: case PXA210_C0:
> + break;
> + default:
> + printf("%s: unrecognized processor: %08x\n",
> + DRIVER_NAME, chiprev);
> + return -ENODEV;
> + }
> +
> + the_controller = dev;
> +
> + /* prepare watchdog timer */
> + dev->watchdog.running = 0;
> + dev->watchdog.period = 5000 * CONFIG_SYS_HZ / 1000000; /* 5 ms */
> + dev->watchdog.function = udc_watchdog;
> +
> + udc_disable(dev);
> + udc_reinit(dev);
> +
> + dev->mach = &mach_info;
> +
> + dev->gadget.name = "pxa2xx_udc";
> + retval = driver->bind(&dev->gadget);
> + if (retval) {
> + printf("bind to driver %s --> error %d\n",
> + DRIVER_NAME, retval);
> + dev->driver = NULL;
> + return retval;
> + }
> +
> + /*
> + * ... then enable host detection and ep0; and we're ready
> + * for set_configuration as well as eventual disconnect.
> + */
> + printf("registered gadget driver '%s'\n", DRIVER_NAME);
> +
> + pullup(dev);
> + dump_state(dev);
> + return 0;
> +}
[...]
> +struct pxa25x_request {
> + struct usb_request req;
> + struct list_head queue;
> +};
> +
> +enum ep0_state {
> + EP0_IDLE,
> + EP0_IN_DATA_PHASE,
> + EP0_OUT_DATA_PHASE,
> + EP0_END_XFER,
> + EP0_STALL,
> +};
> +
> +#define EP0_FIFO_SIZE ((unsigned)16)
Wasn't there something like 16U or something instead of the typecast?
> +#define BULK_FIFO_SIZE ((unsigned)64)
> +#define ISO_FIFO_SIZE ((unsigned)256)
> +#define INT_FIFO_SIZE ((unsigned)8)
> +
> +struct udc_stats {
> + struct ep0stats {
> + unsigned long ops;
> + unsigned long bytes;
> + } read, write;
> + unsigned long irqs;
> +};
> +
> +#ifdef CONFIG_USB_PXA25X_SMALL
> +/* when memory's tight, SMALL config saves code+data. */
> +#define PXA_UDC_NUM_ENDPOINTS 3
> +#endif
> +
> +#ifndef PXA_UDC_NUM_ENDPOINTS
> +#define PXA_UDC_NUM_ENDPOINTS 16
> +#endif
> +
> +struct pxa25x_watchdog {
> + unsigned running:1;
> + ulong period;
> + ulong base;
> + struct pxa25x_udc *udc;
> +
> + void (*function)(struct pxa25x_udc *udc);
> +};
> +
> +struct pxa25x_udc {
> + struct usb_gadget gadget;
> + struct usb_gadget_driver *driver;
> + struct pxa25x_udc_regs *regs;
> +
> + enum ep0_state ep0state;
> + struct udc_stats stats;
> + unsigned got_irq:1,
> + pullup:1,
> + has_cfr:1,
> + req_pending:1,
> + req_std:1,
> + req_config:1,
> + active:1;
> +
> + struct clk *clk;
> + struct pxa2xx_udc_mach_info *mach;
> + u64 dma_mask;
> + struct pxa25x_ep ep[PXA_UDC_NUM_ENDPOINTS];
> +
> + struct pxa25x_watchdog watchdog;
> +};
> +
> +/*------------------------------------------------------------------------
> -*/ +
> +static struct pxa25x_udc *the_controller;
> +
> +/*------------------------------------------------------------------------
> -*/ +
> +#ifdef DEBUG
Functions should certainly not be in a header file.
> +static const char * const state_name[] = {
> + "EP0_IDLE",
> + "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
> + "EP0_END_XFER", "EP0_STALL"
> +};
> +
> +static void
> +dump_udccr(const char *label)
> +{
> + u32 udccr = readl(&UDC_REGS->udccr);
> + debug("%s %02X =%s%s%s%s%s%s%s%s\n",
> + label, udccr,
> + (udccr & UDCCR_REM) ? " rem" : "",
> + (udccr & UDCCR_RSTIR) ? " rstir" : "",
> + (udccr & UDCCR_SRM) ? " srm" : "",
> + (udccr & UDCCR_SUSIR) ? " susir" : "",
> + (udccr & UDCCR_RESIR) ? " resir" : "",
> + (udccr & UDCCR_RSM) ? " rsm" : "",
> + (udccr & UDCCR_UDA) ? " uda" : "",
> + (udccr & UDCCR_UDE) ? " ude" : "");
> +}
> +
> +static void
> +dump_udccs0(const char *label)
> +{
> + u32 udccs0 = readl(&UDC_REGS->udccs[0]);
> +
> + debug("%s %s %02X =%s%s%s%s%s%s%s%s\n",
> + label, state_name[the_controller->ep0state], udccs0,
> + (udccs0 & UDCCS0_SA) ? " sa" : "",
> + (udccs0 & UDCCS0_RNE) ? " rne" : "",
> + (udccs0 & UDCCS0_FST) ? " fst" : "",
> + (udccs0 & UDCCS0_SST) ? " sst" : "",
> + (udccs0 & UDCCS0_DRWF) ? " dwrf" : "",
> + (udccs0 & UDCCS0_FTF) ? " ftf" : "",
> + (udccs0 & UDCCS0_IPR) ? " ipr" : "",
> + (udccs0 & UDCCS0_OPR) ? " opr" : "");
> +}
> +
> +static void
> +dump_state(struct pxa25x_udc *dev)
> +{
> + u32 tmp;
> + unsigned i;
> +
> + debug("%s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
> + state_name[dev->ep0state],
> + readl(&UDC_REGS->uicr1), readl(&UDC_REGS->uicr0),
> + readl(&UDC_REGS->usir1), readl(&UDC_REGS->usir0),
> + readl(&UDC_REGS->ufnrh), readl(&UDC_REGS->ufnrl));
> + dump_udccr("udccr");
> + if (dev->has_cfr) {
> + tmp = readl(&UDC_REGS->udccfr);
> + debug("udccfr %02X =%s%s\n", tmp,
> + (tmp & UDCCFR_AREN) ? " aren" : "",
> + (tmp & UDCCFR_ACM) ? " acm" : "");
> + }
> +
> + if (!dev->driver) {
> + debug("no gadget driver bound\n");
> + return;
> + } else
> + debug("ep0 driver '%s'\n", "ether");
> +
> + dump_udccs0("udccs0");
> + debug("ep0 IN %lu/%lu, OUT %lu/%lu\n",
> + dev->stats.write.bytes, dev->stats.write.ops,
> + dev->stats.read.bytes, dev->stats.read.ops);
> +
> + for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
> + if (dev->ep[i].desc == NULL)
> + continue;
> + debug("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
> + }
> +}
> +
> +#ifdef DEBUG_NOISY
> +# define NOISY 1
> +#else
> +# define NOISY 0
> +#endif
> +
> +#else
> +
> +#define NOISY 0
> +#define dump_udccr(x) do {} while (0)
> +#define dump_udccs0(x) do {} while (0)
> +#define dump_state(x) do {} while (0)
Please make these empty inline functions (for the sake of typechecking, compiler
will optimize them out well).
> +#endif
> +
> +#endif /* __LINUX_USB_GADGET_PXA25X_H */
More information about the U-Boot
mailing list