U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
September 2012
- 180 participants
- 613 discussions

16 Oct '12
From: Pratyush Anand <pratyush.anand(a)st.com>
Driver for designware otg device only implements device functionality
and is meant to be used with usbtty interface.
This driver will work mainly for Control and Bulk endpoints. Periodic
transfer has not been verified using these drivers.
Signed-off-by: Pratyush Anand <pratyush.anand(a)st.com>
Signed-off-by: Amit Virdi <amit.virdi(a)st.com>
---
drivers/serial/usbtty.h | 2 +
drivers/usb/gadget/Makefile | 1 +
drivers/usb/gadget/designware_otg.c | 990 +++++++++++++++++++++++++++++++++++
include/usb/designware_otg.h | 523 ++++++++++++++++++
4 files changed, 1516 insertions(+), 0 deletions(-)
create mode 100644 drivers/usb/gadget/designware_otg.c
create mode 100644 include/usb/designware_otg.h
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
index eb670da..bd3bcbc 100644
--- a/drivers/serial/usbtty.h
+++ b/drivers/serial/usbtty.h
@@ -35,6 +35,8 @@
#include <usb/pxa27x_udc.h>
#elif defined(CONFIG_DW_UDC)
#include <usb/designware_udc.h>
+#elif defined(CONFIG_DW_OTG)
+#include <usb/designware_otg.h>
#endif
#include <version.h>
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 87d1918..ede367e 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -40,6 +40,7 @@ ifdef CONFIG_USB_DEVICE
COBJS-y += core.o
COBJS-y += ep0.o
COBJS-$(CONFIG_DW_UDC) += designware_udc.o
+COBJS-$(CONFIG_DW_OTG) += designware_otg.o
COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o
COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o
COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o
diff --git a/drivers/usb/gadget/designware_otg.c b/drivers/usb/gadget/designware_otg.c
new file mode 100644
index 0000000..5af6940
--- /dev/null
+++ b/drivers/usb/gadget/designware_otg.c
@@ -0,0 +1,990 @@
+/*
+ * Based on drivers/usb/gadget/designware_otg.c
+ * Synopsys DW OTG Device bus interface driver
+ *
+ * (C) Copyright 2011
+ * Pratyush Anand, ST Micoelectronics, pratyush.anand(a)st.com.
+ *
+ * (C) Copyright 2012
+ * Amit Virdi, ST Micoelectronics, amit.virdi(a)st.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usbdevice.h>
+#include <watchdog.h>
+#include "ep0.h"
+#include <usb/designware_otg.h>
+#include <asm/arch/hardware.h>
+
+#define UDC_INIT_MDELAY 80 /* Device settle delay */
+
+static struct urb *ep0_urb;
+static struct usb_device_instance *udc_device;
+
+static struct device_if device_if_mem;
+static struct device_if *dev_if = &device_if_mem;
+
+#if defined(CONFIG_USBD_HS)
+#define CONFIG_USBD_SERIAL_BULK_PKTSIZE UDC_BULK_HS_PACKET_SIZE
+#endif
+
+void udc_set_nak(int epid)
+{
+ setbits_le32(&dev_if->out_ep_regs[epid]->doepctl, SNAK);
+ setbits_le32(&dev_if->in_ep_regs[epid]->diepctl, SNAK);
+}
+
+void udc_unset_nak(int epid)
+{
+ setbits_le32(&dev_if->out_ep_regs[epid]->doepctl, CNAK);
+ setbits_le32(&dev_if->in_ep_regs[epid]->diepctl, CNAK);
+}
+
+static void udc_set_stall(int epid, int dir)
+{
+ if (dir)
+ setbits_le32(&dev_if->in_ep_regs[epid]->diepctl, SSTALL);
+ else
+ setbits_le32(&dev_if->out_ep_regs[epid]->doepctl, SSTALL);
+}
+
+/*
+ * This function enables EP0 OUT to receive SETUP packets and configures EP0
+ * IN for transmitting packets. It is normally called when the "Enumeration
+ * Done" interrupt occurs.
+ */
+static void dwc_otg_ep0_activate(void)
+{
+ struct device_in_ep_regs *in_ep_regs = dev_if->in_ep_regs[0];
+ struct device_out_ep_regs *out_ep_regs = dev_if->out_ep_regs[0];
+
+ /* Read the Device Status and Endpoint 0 Control registers */
+ clrsetbits_le32(&in_ep_regs->diepctl, MPSMSK0, DWC_DEP0CTL_MPS_64);
+
+ /* Enable OUT EP for receive */
+ setbits_le32(&out_ep_regs->doepctl, EPENA);
+}
+
+static struct usb_endpoint_instance *dw_find_ep(int ep)
+{
+ int i;
+
+ for (i = 0; i < udc_device->bus->max_endpoints; i++) {
+ if ((udc_device->bus->endpoint_array[i].endpoint_address &
+ USB_ENDPOINT_NUMBER_MASK) == ep)
+ return &udc_device->bus->endpoint_array[i];
+ }
+ return NULL;
+}
+
+/*
+ * This function reads a packet from the Rx FIFO into the destination buffer.
+ * To read SETUP data use dwc_otg_read_setup_packet.
+ */
+static void dwc_otg_read_packet(struct dwc_ep *ep, u16 bytes)
+{
+ u32 i;
+ int word_count = (bytes + 3) / 4;
+ u32 *fifo = dev_if->data_fifo[0];
+ u32 *data_buff = (u32 *) ep->xfer_buff;
+ u32 unaligned;
+ /*
+ * This requires reading data from the FIFO into a u32 temp buffer,
+ * then moving it into the data buffer.
+ */
+ if ((bytes < 4) && (bytes > 0)) {
+ unaligned = readl(fifo);
+ memcpy(data_buff, &unaligned, bytes);
+ } else {
+ for (i = 0; i < word_count; i++, data_buff++)
+ *data_buff = readl(fifo);
+ }
+}
+
+/* Handle RX transaction on non-ISO endpoint. */
+static void dw_udc_epn_rx(struct dwc_ep *ep, int bcnt)
+{
+ struct urb *urb;
+ struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num);
+
+ if (endpoint) {
+ urb = endpoint->rcv_urb;
+
+ if (urb) {
+ ep->xfer_buff = urb->buffer + urb->actual_length;
+ dwc_otg_read_packet(ep, bcnt);
+ usbd_rcv_complete(endpoint, bcnt, 0);
+ }
+ }
+}
+
+/*
+ * This function writes a packet into the Tx FIFO associated with the EP.
+ * The buffer is padded to DWORD on a per packet basis in
+ * slave/dma mode if the MPS is not DWORD aligned. The last packet, if
+ * short, is also padded to a multiple of DWORD.
+ *
+ * ep->xfer_buff always starts DWORD aligned in memory and is a
+ * multiple of DWORD in length
+ *
+ * ep->xfer_len can be any number of bytes
+ *
+ * FIFO access is DWORD
+ */
+static void dwc_otg_ep_write_packet(struct dwc_ep *ep)
+{
+ u32 i;
+ u32 dword_count;
+ u32 *fifo;
+ u32 *data_buff = (u32 *) ep->xfer_buff;
+ u32 temp, unaligned;
+ u32 timeout = 1; /* 1ms as the timeout */
+ ulong start;
+ struct device_in_ep_regs *in_ep_regs = dev_if->in_ep_regs[ep->num];
+ struct core_global_regs *core_global_regs = dev_if->core_global_regs;
+
+ /*
+ * Find the DWORD length, padded by extra bytes as neccessary if MPS
+ * is not a multiple of DWORD
+ */
+ dword_count = (ep->xfer_len + 3) / 4;
+ fifo = dev_if->data_fifo[ep->num];
+
+ /* program pkt count */
+ temp = ep->xfer_len;
+ temp |= (1 << PKTCNT_SHIFT);
+ writel(temp, &in_ep_regs->dieptsiz);
+
+ /* enable EP*/
+ setbits_le32(&in_ep_regs->diepctl, EPENA | CNAK);
+
+ /* clear TX Fifo Empty intr*/
+ writel(NPTXFEMPTY, &core_global_regs->gintsts);
+
+ setbits_le32(&core_global_regs->gintmsk, NPTXFEMPTY);
+
+ start = get_timer(0);
+ while (!(readl(&core_global_regs->gintsts) & NPTXFEMPTY)) {
+ if (get_timer(start) > timeout) {
+ printf("%s: NPTXFEMPTY: TimeOUT\n", __func__);
+ WATCHDOG_RESET();
+ }
+ }
+
+ /* write to fifo */
+ if ((ep->xfer_len < 4) && (ep->xfer_len > 0)) {
+ memcpy(&unaligned, data_buff, ep->xfer_len);
+ *fifo = unaligned;
+ } else {
+ for (i = 0; i < dword_count; i++, data_buff++)
+ *fifo = *data_buff;
+ }
+
+ writel(NPTXFEMPTY, &core_global_regs->gintsts);
+
+ /* check for transfer completion*/
+ start = get_timer(0);
+ while (!(readl(&in_ep_regs->diepint) & XFERCOMPL)) {
+ if (get_timer(start) > timeout) {
+ printf("%s: XFERCOMPLE: TimeOUT\n", __func__);
+ WATCHDOG_RESET();
+ }
+ }
+
+ writel(XFERCOMPL, &in_ep_regs->diepint);
+ clrbits_le32(&core_global_regs->gintmsk, NPTXFEMPTY);
+}
+
+/* Handle TX transaction on non-ISO endpoint. */
+static void dw_udc_epn_tx(struct dwc_ep *ep)
+{
+ struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num);
+ struct urb *urb = endpoint->tx_urb;
+ int align;
+
+ if (!endpoint)
+ return;
+
+ /*
+ * We need to transmit a terminating zero-length packet now if
+ * we have sent all of the data in this URB and the transfer
+ * size was an exact multiple of the packet size.
+ */
+ if (urb && (endpoint->last == endpoint->tx_packetSize) &&
+ (urb->actual_length - endpoint->sent -
+ endpoint->last == 0)) {
+ /* handle zero length packet here */
+ ep->xfer_len = 0;
+ dwc_otg_ep_write_packet(ep);
+ }
+
+ if (urb && urb->actual_length) {
+ /* retire the data that was just sent */
+ usbd_tx_complete(endpoint);
+ /*
+ * Check to see if we have more data ready to transmit
+ * now.
+ */
+ if (urb && urb->actual_length) {
+ /* write data to FIFO */
+ ep->xfer_len = MIN(urb->actual_length - endpoint->sent,
+ endpoint->tx_packetSize);
+
+ if (ep->xfer_len) {
+ ep->xfer_buff = urb->buffer + endpoint->sent;
+
+ /*
+ * This ensures that USBD packet fifo is
+ * accessed through word aligned pointer or
+ * through non word aligned pointer but only
+ * with a max length to make the next packet
+ * word aligned
+ */
+
+ align = ((ulong)ep->xfer_buff % sizeof(int));
+ if (align)
+ ep->xfer_len = MIN(ep->xfer_len,
+ sizeof(int)-align);
+
+ dwc_otg_ep_write_packet(ep);
+ }
+ endpoint->last = ep->xfer_len;
+
+ }
+ }
+}
+
+/* This function returns pointer to out ep struct with number num */
+static struct dwc_ep *get_out_ep(u32 num)
+{
+ u32 i;
+ int num_out_eps = MAX_EPS_CHANNELS;
+ struct dwc_pcd *pcd = &dev_if->pcd;
+
+ if (num == 0)
+ return &pcd->ep0;
+
+ for (i = 0; i < num_out_eps; ++i) {
+ if (pcd->out_ep[i].num == num)
+ return &pcd->out_ep[i];
+ }
+
+ return 0;
+}
+
+/* This function returns pointer to in ep struct with number num */
+static struct dwc_ep *get_in_ep(u32 num)
+{
+ u32 i;
+ int num_out_eps = MAX_EPS_CHANNELS;
+ struct dwc_pcd *pcd = &dev_if->pcd;
+
+ if (num == 0)
+ return &pcd->ep0;
+
+ for (i = 0; i < num_out_eps; ++i) {
+ if (pcd->in_ep[i].num == num)
+ return &pcd->in_ep[i];
+ }
+
+ return 0;
+}
+
+/*
+ * This function reads the 8 bytes of the setup packet from the Rx FIFO into the
+ * destination buffer. It is called from the Rx Status Queue Level (RxStsQLvl)
+ * interrupt routine when a SETUP packet has been received in Slave mode.
+ */
+static void dwc_otg_read_setup_packet(u32 *dest)
+{
+ dest[0] = readl(dev_if->data_fifo[0]);
+ dest[1] = readl(dev_if->data_fifo[0]);
+}
+
+/*
+ * This function handles the Rx Status Queue Level Interrupt, which
+ * indicates that there is a least one packet in the Rx FIFO. The
+ * packets are moved from the FIFO to memory, where they will be
+ * processed when the Endpoint Interrupt Register indicates Transfer
+ * Complete or SETUP Phase Done.
+ *
+ * Repeat the following until the Rx Status Queue is empty:
+ * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
+ * info
+ * -# If Receive FIFO is empty then skip to step Clear the interrupt
+ * and exit
+ * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
+ * SETUP data to the buffer
+ * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
+ * to the destination buffer
+ */
+static int dwc_otg_pcd_handle_rx_status_q_level_intr(void)
+{
+ struct core_global_regs *global_regs = dev_if->core_global_regs;
+ struct dwc_pcd *pcd = &dev_if->pcd;
+ u32 status;
+ struct dwc_ep *ep;
+ u32 bcnt;
+
+ /* Disable the Rx Status Queue Level interrupt */
+ clrbits_le32(&global_regs->gintmsk, RXSTSQLVL);
+
+ /* Get the Status from the top of the FIFO */
+ status = readl(&global_regs->grxstsp);
+ /* Get pointer to EP structure */
+ ep = get_out_ep((status & EPNUMMSK) >> EPNUM_SHIFT);
+ bcnt = (status & BCNTMSK) >> BCNT_SHIFT;
+
+ switch ((status & PKTSTSMSK) >> PKTSTS_SHIFT) {
+ case DWC_DSTS_GOUT_NAK:
+ break;
+ case DWC_STS_DATA_UPDT:
+ if (bcnt)
+ dw_udc_epn_rx(ep, bcnt);
+ break;
+ case DWC_STS_XFER_COMP:
+ break;
+ case DWC_DSTS_SETUP_COMP:
+ break;
+ case DWC_DSTS_SETUP_UPDT:
+ dwc_otg_read_setup_packet((u32 *)pcd->req);
+ break;
+ default:
+ break;
+ }
+
+ /* Enable the Rx Status Queue Level interrupt */
+ setbits_le32(&global_regs->gintmsk, RXSTSQLVL);
+
+ /* Clear interrupt */
+ setbits_le32(&global_regs->gintsts, RXSTSQLVL);
+
+ return 1;
+}
+
+/*
+ * This function starts the Zero-Length Packet for the IN status phase
+ * of a 2 stage control transfer.
+ */
+static void do_setup_in_status_phase(struct device_if *dev_if)
+{
+ struct device_out_ep_regs *out_regs =
+ dev_if->out_ep_regs[0];
+
+ setbits_le32(&out_regs->doeptsiz, PKTCNT_SHIFT);
+
+ setbits_le32(&out_regs->doepctl, CNAK | EPENA);
+}
+
+/*
+ * This function handles EP0 Control transfers.
+ *
+ * The state of the control tranfers are tracked in ep0state
+ *
+ * A flag set indicates that it is not the first packet, so do not
+ * process setup data now. it has alreday been processed, just send the
+ * next data packet
+ */
+static void handle_ep0(int in_flag)
+{
+ struct dwc_pcd *pcd = &dev_if->pcd;
+ struct dwc_ep *ep0 = &pcd->ep0;
+ struct usb_device_request *ctrl = pcd->req;
+
+ /* handle inepint, only when more than 64 bytes to transfer*/
+ if (in_flag & !ep0_urb->actual_length)
+ return;
+
+ if (!ep0_urb->actual_length) {
+ if (ep0_recv_setup(ep0_urb)) {
+ udc_set_stall(0, ctrl->bmRequestType & USB_DIR_IN);
+ return;
+ }
+ ep0->xfer_buff = (u8 *)ep0_urb->buffer;
+ } else
+ ep0->xfer_buff += EP0_MAX_PACKET_SIZE;
+
+ if (ep0_urb->actual_length <= EP0_MAX_PACKET_SIZE) {
+ ep0->xfer_len = ep0_urb->actual_length;
+ ep0_urb->actual_length = 0;
+ } else {
+ ep0->xfer_len = EP0_MAX_PACKET_SIZE;
+ ep0_urb->actual_length -= EP0_MAX_PACKET_SIZE;
+ }
+
+ if (ctrl->bmRequestType & USB_DIR_IN) {
+ dwc_otg_ep_write_packet(ep0);
+ if (!ep0_urb->actual_length)
+ do_setup_in_status_phase(dev_if);
+ } else {
+ if (!ctrl->wLength)
+ dwc_otg_ep_write_packet(ep0);
+ else
+ udc_set_stall(0, ctrl->bmRequestType & USB_DIR_OUT);
+ }
+}
+
+/*
+ * This function reads the Device All Endpoints Interrupt register and
+ * returns the OUT endpoint interrupt bits.
+ */
+static u32 dwc_otg_read_dev_all_out_ep_intr(void)
+{
+ u32 v;
+
+ v = readl(&dev_if->dev_global_regs->daint) &
+ readl(&dev_if->dev_global_regs->daintmsk);
+ return v >> 16;
+}
+
+/*
+ * This function reads the Device All Endpoints Interrupt register and
+ * returns the IN endpoint interrupt bits.
+ */
+static u32 dwc_otg_read_dev_all_in_ep_intr(void)
+{
+ u32 v;
+
+ v = readl(&dev_if->dev_global_regs->daint) &
+ readl(&dev_if->dev_global_regs->daintmsk);
+ return v & 0xffff;
+}
+
+/* This function returns the Device OUT EP Interrupt register */
+static u32 dwc_otg_read_doep_intr(struct dwc_ep *ep)
+{
+ u32 v;
+
+ v = readl(&dev_if->out_ep_regs[ep->num]->doepint) &
+ readl(&dev_if->dev_global_regs->doepmsk);
+ return v;
+}
+
+/*This function returns the Device IN EP Interrupt register */
+static u32 dwc_otg_read_diep_intr(struct dwc_ep *ep)
+{
+ u32 v;
+
+ v = readl(&dev_if->in_ep_regs[ep->num]->diepint) &
+ readl(&dev_if->dev_global_regs->diepmsk);
+ return v;
+}
+
+/*
+ * This function configures EPO to receive SETUP packets.
+ *
+ * Program the following fields in the endpoint specific registers for Control
+ * OUT EP 0, in order to receive a setup packet:
+ *
+ * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back setup packets)
+ *
+ * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back to back setup
+ * packets)
+ *
+ * In DMA mode, DOEPDMA0 Register with a memory address to store any setup
+ * packets received
+ */
+static void ep0_out_start(void)
+{
+ u32 temp;
+
+ /* program transfer size*/
+ temp = 8 * 3;
+ /* program packet count*/
+ temp |= PKTCNT;
+ /* program setup packet count */
+ temp |= (3 << SUPCNT_SHIFT);
+ writel(temp, &dev_if->out_ep_regs[0]->doeptsiz);
+}
+
+/* should be called after set address is received */
+void udc_set_address_controller(u32 address)
+{
+ u32 dcfg;
+
+ dcfg = readl(&dev_if->dev_global_regs->dcfg);
+ dcfg &= ~DEVADDRMSK;
+ dcfg |= address << DEVADDR_SHIFT;
+ writel(dcfg, &dev_if->dev_global_regs->dcfg);
+
+ usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+}
+
+/* should be called after set configuration is received */
+static void dwc_otg_bulk_out_activate(void)
+{
+ struct device_out_ep_regs *out_regs =
+ dev_if->out_ep_regs[UDC_OUT_ENDPOINT];
+ struct device_global_regs *dev_global_regs
+ = dev_if->dev_global_regs;
+
+ setbits_le32(&dev_global_regs->daintmsk,
+ (UDC_OUT_ENDPOINT + DAINTMASK_OUT_SHIFT));
+
+ setbits_le32(&out_regs->doeptsiz,
+ CONFIG_USBD_SERIAL_BULK_PKTSIZE | PKTCNT_SHIFT);
+
+ clrsetbits_le32(&out_regs->doepctl, DOEPCTL_MPSMSK | EPTYPEMSK,
+ CONFIG_USBD_SERIAL_BULK_PKTSIZE | CNAK | EPENA |
+ USBACTEP | DATA0PID | (EPTYPE_BULK << EPTYPE_SHIFT));
+}
+
+/* should be called after set configuration is received */
+static void dwc_otg_bulk_in_activate(void)
+{
+ struct device_in_ep_regs *in_regs =
+ dev_if->in_ep_regs[UDC_IN_ENDPOINT];
+ struct device_global_regs *dev_global_regs
+ = dev_if->dev_global_regs;
+
+ setbits_le32(&dev_global_regs->daintmsk,
+ (UDC_IN_ENDPOINT + DAINTMASK_IN_SHIFT));
+
+ clrsetbits_le32(&in_regs->diepctl,
+ DIEPCTL_MPSMSK | EPTYPEMSK,
+ CONFIG_USBD_SERIAL_BULK_PKTSIZE | USBACTEP | DATA0PID |
+ (EPTYPE_BULK << EPTYPE_SHIFT));
+}
+
+static void dwc_otg_int_in_activate(void)
+{
+ struct device_in_ep_regs *in_regs =
+ dev_if->in_ep_regs[UDC_INT_ENDPOINT];
+ struct device_global_regs *dev_global_regs
+ = dev_if->dev_global_regs;
+
+ setbits_le32(&dev_global_regs->daintmsk,
+ (UDC_INT_ENDPOINT + DAINTMASK_IN_SHIFT));
+
+ clrsetbits_le32(&in_regs->diepctl,
+ DIEPCTL_MPSMSK | EPTYPEMSK,
+ UDC_INT_PACKET_SIZE | USBACTEP | DATA0PID |
+ (EPTYPE_INT << EPTYPE_SHIFT));
+}
+
+/* should be called after set configuration is received */
+void udc_set_configuration_controller(u32 config)
+{
+ dwc_otg_bulk_out_activate();
+ dwc_otg_bulk_in_activate();
+ dwc_otg_int_in_activate();
+ usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+}
+
+/* should be called to receive next packet */
+static void dwc_otg_bulk_out_enable(void)
+{
+ struct device_out_ep_regs *out_regs =
+ dev_if->out_ep_regs[UDC_OUT_ENDPOINT];
+
+ setbits_le32(&out_regs->doeptsiz, PKTCNT_SHIFT |
+ CONFIG_USBD_SERIAL_BULK_PKTSIZE);
+ setbits_le32(&out_regs->doepctl, CNAK | EPENA);
+}
+
+/* This interrupt indicates that an OUT EP has a pending Interrupt. */
+
+static int dwc_otg_pcd_handle_out_ep_intr(void)
+{
+ u32 ep_intr;
+ u32 doepint;
+ u32 epnum = 0;
+ struct dwc_ep *ep;
+ struct device_out_ep_regs **out_ep_regs
+ = dev_if->out_ep_regs;
+
+ /* Read in the device interrupt bits */
+ ep_intr = dwc_otg_read_dev_all_out_ep_intr();
+ while (ep_intr) {
+ if (ep_intr & 0x1) {
+ ep = get_out_ep(epnum);
+ doepint = dwc_otg_read_doep_intr(ep);
+
+ /* Transfer complete */
+ if (doepint & XFERCOMPL) {
+ /* Clear xfercompl */
+ writel(XFERCOMPL, &out_ep_regs[epnum]->doepint);
+ if (!epnum)
+ ep0_out_start();
+ else if (epnum == UDC_OUT_ENDPOINT)
+ dwc_otg_bulk_out_enable();
+ }
+ /* Setup Phase Done (control EPs) */
+ if (doepint & SETUP) {
+ writel(SETUP, &out_ep_regs[epnum]->doepint);
+ handle_ep0(0);
+ }
+ }
+ epnum++;
+ ep_intr >>= 1;
+ }
+ return 1;
+}
+
+/* This interrupt indicates that an IN EP has a pending Interrupt. */
+
+static int dwc_otg_pcd_handle_in_ep_intr(void)
+{
+ u32 ep_intr;
+ u32 diepint;
+ u32 epnum = 0;
+ struct dwc_ep *ep;
+ struct device_in_ep_regs **in_ep_regs
+ = dev_if->in_ep_regs;
+
+ /* Read in the device interrupt bits */
+ ep_intr = dwc_otg_read_dev_all_in_ep_intr();
+ while (ep_intr) {
+ if (!(ep_intr & 0x1))
+ continue;
+ ep = get_in_ep(epnum);
+ diepint = dwc_otg_read_diep_intr(ep);
+
+ /* IN token received when txfifo empty */
+ if (diepint & INTKNTXFEMP) {
+ /* Clear xfercompl */
+ writel(INTKNTXFEMP,
+ &in_ep_regs[epnum]->diepint);
+ if (!epnum)
+ handle_ep0(1);
+ else if (epnum == UDC_IN_ENDPOINT)
+ dw_udc_epn_tx(ep);
+ }
+ epnum++;
+ ep_intr >>= 1;
+ }
+ return 1;
+}
+
+static void dwc_otg_flush_tx_fifo(const int num)
+{
+ struct core_global_regs *global_regs = dev_if->core_global_regs;
+ u32 val = 0;
+ u32 timeout = 10; /* 10ms timeout */
+ ulong start = 0;
+
+ clrsetbits_le32(&global_regs->grstctl, TXFNUM,
+ TXFFLSH | (num << TXFNUM_SHIFT));
+
+ start = get_timer(0);
+ while (val & TXFFLSH) {
+ if (get_timer(start) > timeout)
+ WATCHDOG_RESET();
+
+ val = readl(&global_regs->grstctl);
+ }
+
+ /* Wait for 3 PHY Clocks */
+ udelay(1);
+}
+
+static void dwc_otg_flush_rx_fifo(void)
+{
+ struct core_global_regs *global_regs = dev_if->core_global_regs;
+ int timeout = 10; /* 10 ms timeout */
+ u32 val = 0;
+ ulong start;
+
+ setbits_le32(&global_regs->grstctl, RXFFLSH);
+
+ start = get_timer(0);
+ while (val & RXFFLSH) {
+ if (get_timer(start) > timeout)
+ WATCHDOG_RESET();
+
+ val = readl(&global_regs->grstctl);
+ }
+
+ /* Wait for 3 PHY Clocks */
+ udelay(1);
+}
+
+/*
+ * This interrupt occurs when a USB Reset is detected. When the USB Reset
+ * Interrupt occurs the device state is set to DEFAULT and the EP0 state is set
+ * to IDLE.
+ *
+ */
+static int dwc_otg_pcd_handle_usb_reset_intr(void)
+{
+ u32 temp;
+ u32 i;
+ struct device_out_ep_regs **out_ep_regs
+ = dev_if->out_ep_regs;
+ struct device_global_regs *dev_global_regs
+ = dev_if->dev_global_regs;
+ struct core_global_regs *core_global_regs
+ = dev_if->core_global_regs;
+ /* Set NAK for all OUT EPs */
+ for (i = 0; i < MAX_EPS_CHANNELS; i++)
+ setbits_le32(&out_ep_regs[i]->doepctl, SNAK);
+
+ /* Flush the NP Tx FIFO */
+ dwc_otg_flush_tx_fifo(DWC_GRSTCTL_TXFNUM_ALL);
+ dwc_otg_flush_rx_fifo();
+ setbits_le32(&dev_global_regs->daintmsk, DAINTMASK_IN_SHIFT |
+ DAINTMASK_OUT_SHIFT);
+
+ setbits_le32(&dev_global_regs->doepmsk, SETUPMSK | XFERCOMPLMSK |
+ AHBERRMSK | EPDISABLEDMSK);
+
+ writel(INTKNTXFEMP, &dev_global_regs->diepmsk);
+
+ setbits_le32(&core_global_regs->gintmsk, GOUTNAKEFF);
+
+ /* program fifo size for ep0 */
+ writel(DWC_OTG_RX_FIFO_SIZE, &core_global_regs->grxfsiz);
+
+ temp = readl(&dev_if->in_ep_regs[0]->diepctl);
+ temp &= 0xFFC3FFFF; /* TxFNumBF = 0, bits 25:22 */
+ writel(temp, &dev_if->in_ep_regs[0]->diepctl);
+
+ temp = readl(&core_global_regs->gnptxfsiz);
+
+ writel((DWC_OTG_RX_FIFO_SIZE | DWC_OTG_NPTX_FIFO_SIZE << 16),
+ &core_global_regs->gnptxfsiz);
+
+ /* Reset Device Address */
+ clrbits_le32(&dev_global_regs->dcfg, DEVADDRMSK);
+
+ /* setup EP0 to receive SETUP packets */
+ ep0_out_start();
+
+ /* Clear interrupt */
+ writel(USBRESET, &core_global_regs->gintsts);
+
+ usbd_device_event_irq(udc_device, DEVICE_HUB_CONFIGURED, 0);
+
+ return 1;
+}
+
+/*
+ * Read the device status register and set the device speed in the
+ * data structure.
+ * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
+ */
+static int dwc_otg_pcd_handle_enum_done_intr(void)
+{
+ struct core_global_regs *global_regs = dev_if->core_global_regs;
+
+ dwc_otg_ep0_activate();
+
+ clrsetbits_le32(&global_regs->gusbcfg, USBTRDTIMMSK, PHYIF_16BIT |
+ (USBTRDTIM_MAC_IF_8BIT_UTMI << USBTRDTIM_SHIFT));
+
+ /* Clear interrupt */
+ writel(ENUMDONE, &global_regs->gintsts);
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+
+ return 1;
+}
+
+static u32 dwc_otg_read_core_intr(void)
+{
+ return readl(&dev_if->core_global_regs->gintsts) &
+ readl(&dev_if->core_global_regs->gintmsk);
+}
+
+static void dwc_otg_init(const void *reg_base)
+{
+ struct dwc_pcd *pcd = &dev_if->pcd;
+ u32 offset;
+ u32 i;
+
+ dev_if->core_global_regs = (struct core_global_regs *) reg_base;
+ dev_if->dev_global_regs = (struct device_global_regs *) ((u32)reg_base +
+ DWC_DEV_GLOBAL_REG_OFFSET);
+
+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+ offset = i * DWC_EP_REG_OFFSET;
+
+ dev_if->in_ep_regs[i] = (struct device_in_ep_regs *)
+ ((u32)reg_base + DWC_DEV_IN_EP_REG_OFFSET + offset);
+
+ dev_if->out_ep_regs[i] = (struct device_out_ep_regs *)
+ ((u32)reg_base + DWC_DEV_OUT_EP_REG_OFFSET + offset);
+ }
+
+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+ dev_if->data_fifo[i] =
+ (u32 *) ((u32)reg_base + DWC_OTG_DATA_FIFO_OFFSET +
+ (i * DWC_OTG_DATA_FIFO_SIZE));
+ }
+
+ dev_if->speed = 0; /* unknown */
+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+ pcd->in_ep[i].num = i;
+ pcd->out_ep[i].num = i;
+ }
+}
+
+/*
+ * This function initializes the DWC_otg controller registers and prepares the
+ * core for device mode
+ */
+static void dwc_otg_core_init(void)
+{
+ struct core_global_regs *global_regs = dev_if->core_global_regs;
+
+ /* Step 1: Program the GAHBCFG Register. */
+ setbits_le32(&global_regs->gahbcfg, DWC_NPTXEMPTYLVL_EMPTY |
+ DWC_PTXEMPTYLVL_EMPTY);
+
+ /* Step 2: write usbcfg regs*/
+ setbits_le32 (&global_regs->gusbcfg, SRPCAP | HNPCAP);
+
+ /* step3: write int_msk reg*/
+ setbits_le32(&global_regs->gintmsk, USBRESET | ENUMDONE | RXSTSQLVL |
+ OUTEPINTR | INEPINTR);
+}
+
+/* Switch on the UDC */
+static void usbotg_init(void)
+{
+ udc_device = NULL;
+ dwc_otg_init((void *)CONFIG_SYS_USBD_BASE);
+
+ /* Initialize the DWC_otg core. */
+ dwc_otg_core_init();
+
+}
+
+void udc_irq(void)
+{
+ u32 status;
+
+ status = dwc_otg_read_core_intr();
+ while (status) {
+ if (status & USBRESET)
+ dwc_otg_pcd_handle_usb_reset_intr();
+ if (status & ENUMDONE)
+ dwc_otg_pcd_handle_enum_done_intr();
+ if (status & RXSTSQLVL)
+ dwc_otg_pcd_handle_rx_status_q_level_intr();
+ if (status & OUTEPINTR)
+ dwc_otg_pcd_handle_out_ep_intr();
+ if (status & INEPINTR)
+ dwc_otg_pcd_handle_in_ep_intr();
+ status = dwc_otg_read_core_intr();
+ }
+
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+ udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK);
+ return 0;
+}
+
+static void udc_enable(struct usb_device_instance *device)
+{
+ struct dwc_pcd *pcd = &dev_if->pcd;
+
+ /* Save the device structure pointer */
+ udc_device = device;
+
+ /* Setup ep0 urb */
+ if (!ep0_urb) {
+ ep0_urb =
+ usbd_alloc_urb(udc_device,
+ udc_device->bus->endpoint_array);
+ pcd->req =
+ (struct usb_device_request *)&ep0_urb->device_request;
+ pcd->ep0.xfer_buff = (u8 *)ep0_urb->buffer;
+ } else {
+ printf("udc_enable: ep0_urb already allocated %p\n",
+ ep0_urb);
+ }
+}
+
+void udc_connect(void)
+{
+ struct device_global_regs *dev_regs = dev_if->dev_global_regs;
+
+ /* remove soft disconnect */
+ clrbits_le32(&dev_regs->dctl, SFTDISCON);
+}
+
+void udc_disconnect(void)
+{
+ struct device_global_regs *dev_regs = dev_if->dev_global_regs;
+
+ /* soft disconnect */
+ setbits_le32(&dev_regs->dctl, SFTDISCON);
+
+ udelay(150);
+}
+
+void udc_startup_events(struct usb_device_instance *device)
+{
+ /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
+ usbd_device_event_irq(device, DEVICE_INIT, 0);
+
+ /*
+ * The DEVICE_CREATE event puts the USB device in the state
+ * STATE_ATTACHED.
+ */
+ usbd_device_event_irq(device, DEVICE_CREATE, 0);
+
+ /*
+ * Some USB controller driver implementations signal
+ * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
+ * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
+ * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
+ * The DW USB client controller has the capability to detect when the
+ * USB cable is connected to a powered USB bus, so we will defer the
+ * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later.
+ */
+
+ udc_enable(device);
+
+}
+
+void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
+ struct usb_endpoint_instance *endpoint)
+{
+ /*
+ * Nothing to do here. Hob of this function has laready been
+ * done during init.
+ */
+}
+
+int is_usbd_high_speed(void)
+{
+ struct device_global_regs *dev_regs = dev_if->dev_global_regs;
+ u32 dsts;
+
+ dsts = readl(&dev_regs->dsts);
+ dsts &= ENUMSPDMSK;
+ if (dsts == DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ)
+ return 1;
+ else
+ return 0;
+}
+
+int udc_init(void)
+{
+ phy_init();
+ udc_disconnect();
+ usbotg_init();
+ return 0;
+}
diff --git a/include/usb/designware_otg.h b/include/usb/designware_otg.h
new file mode 100644
index 0000000..053a324
--- /dev/null
+++ b/include/usb/designware_otg.h
@@ -0,0 +1,523 @@
+/*
+ * (C) Copyright 2011
+ * Pratyush Anand, ST Micoelectronics, pratyush.anand(a)st.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ */
+
+#ifndef __DW_OTG_H
+#define __DW_OTG_H
+
+#include "usbdevice.h"
+/* USBTTY definitions */
+#define EP0_MAX_PACKET_SIZE 64
+#define UDC_INT_ENDPOINT 1
+#define UDC_INT_PACKET_SIZE 64
+#define UDC_OUT_ENDPOINT 2
+#define UDC_BULK_PACKET_SIZE 512
+#if defined(CONFIG_USBD_HS)
+#define UDC_BULK_HS_PACKET_SIZE 512
+#endif
+#define UDC_IN_ENDPOINT 3
+#define UDC_OUT_PACKET_SIZE 64
+#define UDC_IN_PACKET_SIZE 64
+
+/* UDC endpoint definitions */
+#define UDC_EP0 0
+#define UDC_EP1 1
+#define UDC_EP2 2
+#define UDC_EP3 3
+
+#define CMD_SIZE 12
+/* OTG Register Definitions */
+
+/*
+ * The application interfaces with the HS OTG core by reading from and
+ * writing to the Control and Status Register (CSR) space through the
+ * AHB Slave interface. These registers are 32 bits wide, and the
+ * addresses are 32-bit-block aligned.
+ * CSRs are classified as follows:
+ * - Core Global Registers
+ * - Device Mode Registers
+ * - Device Global Registers
+ * - Device Endpoint Specific Registers
+ * - Host Mode Registers
+ * - Host Global Registers
+ * - Host Port CSRs
+ * - Host Channel Specific Registers
+ *
+ * Only the Core Global registers can be accessed in both Device and
+ * Host modes. When the HS OTG core is operating in one mode, either
+ * Device or Host, the application must not access registers from the
+ * other mode. When the core switches from one mode to another, the
+ * registers in the new mode of operation must be reprogrammed as they
+ * would be after a power-on reset.
+ */
+
+/*
+ * DWC_otg Core registers. The core_global_regs structure defines the
+ * size and relative field offsets for the Core Global registers.
+ */
+struct core_global_regs {
+ /* OTG Control and Status Register. Offset: 000h */
+ u32 gotgctl;
+ /* OTG Interrupt Register. Offset: 004h */
+ u32 gotgint;
+ /* Core AHB Configuration Register. Offset: 008h */
+ u32 gahbcfg;
+
+#define DWC_GLBINTRMASK 0x0001
+#define DWC_DMAENABLE 0x0020
+#define DWC_NPTXEMPTYLVL_EMPTY 0x0080
+#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000
+#define DWC_PTXEMPTYLVL_EMPTY 0x0100
+#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000
+
+ /* Core USB Configuration Register. Offset: 00Ch */
+ u32 gusbcfg;
+#define PHYIF_16BIT (1 << 3)
+#define SRPCAP (1 << 8)
+#define HNPCAP (1 << 9)
+#define TERM_SEL_DL_PULSE (1 << 22)
+#define USBTRDTIM_SHIFT 10
+#define USBTRDTIMMSK (0xF << USBTRDTIM_SHIFT)
+#define USBTRDTIM_MAC_IF_8BIT_UTMI 0x9
+#define USBTRDTIM_MAC_IF_16BIT_UTMI 0x5
+ /* Core Reset Register. Offset: 010h */
+ u32 grstctl;
+#define DWC_GRSTCTL_TXFNUM_ALL 0x10
+#define CSFTRST (1 << 0)
+#define INTKNQFLSH (1 << 3)
+#define RXFFLSH (1 << 4)
+#define TXFFLSH (1 << 5)
+#define TXFNUM_SHIFT 6
+#define TXFNUM (0x1F << TXFNUM_SHIFT)
+#define AHBIDLE ((u32)1 << 31)
+ /* Core Interrupt Register. Offset: 014h */
+ u32 gintsts;
+#define RXSTSQLVL (1 << 4)
+#define NPTXFEMPTY (1 << 5)
+#define GOUTNAKEFF (1 << 7)
+#define USBRESET (1 << 12)
+#define ENUMDONE (1 << 13)
+#define INEPINTR (1 << 18)
+#define OUTEPINTR (1 << 19)
+ /* Core Interrupt Mask Register. Offset: 018h */
+ u32 gintmsk;
+ /*
+ * Receive Status Queue Read Register
+ * (Read Only) Offset: 01Ch
+ */
+ u32 grxstsr;
+ /*
+ * Receive Status Queue Read & POP Register
+ * (Read Only) Offset: 020h
+ */
+ u32 grxstsp;
+#define DWC_STS_DATA_UPDT 0x2 /* OUT Data Packet */
+#define DWC_STS_XFER_COMP 0x3 /* OUT Data Transfer Complete */
+#define DWC_DSTS_GOUT_NAK 0x1 /* Global OUT NAK */
+#define DWC_DSTS_SETUP_COMP 0x4 /* Setup Phase Complete */
+#define DWC_DSTS_SETUP_UPDT 0x6 /* SETUP Packet */
+#define EPNUM_SHIFT 0
+#define EPNUMMSK (0xF << EPNUM_SHIFT)
+#define BCNT_SHIFT 4
+#define BCNTMSK (0x7FF << BCNT_SHIFT)
+#define PKTSTS_SHIFT 17
+#define PKTSTSMSK (0xF << PKTSTS_SHIFT)
+ /* Receive FIFO Size Register. Offset: 024h */
+ u32 grxfsiz;
+#define dwc_param_dev_rx_fifo_size_default 1064
+ /* Non Periodic Transmit FIFO Size Register. Offset: 028h */
+ u32 gnptxfsiz;
+#define dwc_param_dev_nperio_tx_fifo_size_default 1024
+#define DWC_OTG_RX_FIFO_SIZE 0x200
+#define DWC_OTG_NPTX_FIFO_SIZE 0x200
+ /*
+ * Non Periodic Transmit FIFO/Queue Status Register
+ * (Read Only). Offset: 02Ch
+ */
+ u32 gnptxsts;
+#define NPTXQSPCAVAIL_SHIFT 16
+#define NPTXQSPCAVAILMSK (0xFF << NPTXQSPCAVAIL_SHIFT)
+#define NPTXFSPCAVAIL_SHIFT 0
+#define NPTXFSPCAVAILMSK (0xFFFF << NPTXFSPCAVAIL_SHIFT)
+ /* I2C Access Register. Offset: 030h */
+ u32 gi2cctl;
+ /* PHY Vendor Control Register. Offset: 034h */
+ u32 gpvndctl;
+ /* General Purpose Input/Output Register. Offset: 038h */
+ u32 ggpio;
+ /* User ID Register. Offset: 03Ch */
+ u32 guid;
+ /* Synopsys ID Register (Read Only). Offset: 040h */
+ u32 gsnpsid;
+ /* User HW Config1 Register (Read Only). Offset: 044h */
+ u32 ghwcfg1;
+ /* User HW Config2 Register (Read Only). Offset: 048h */
+
+ u32 ghwcfg2;
+#define DWC_SLAVE_ONLY_ARCH 0
+#define DWC_EXT_DMA_ARCH 1
+#define DWC_INT_DMA_ARCH 2
+
+#define DWC_MODE_HNP_SRP_CAPABLE 0
+#define DWC_MODE_SRP_ONLY_CAPABLE 1
+#define DWC_MODE_NO_HNP_SRP_CAPABLE 2
+#define DWC_MODE_SRP_CAPABLE_DEVICE 3
+#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4
+#define DWC_MODE_SRP_CAPABLE_HOST 5
+#define DWC_MODE_NO_SRP_CAPABLE_HOST 6
+#define DYNAMIC_FIFO (1 << 19)
+#define NUM_DEV_EP_SHIFT 10
+#define NUM_DEV_EP (0xF << NUM_DEV_EP_SHIFT)
+#define HSPHYTYPE_SHIFT 6
+#define HSPHYTYPEMSK (3 << HSPHYTYPE_SHIFT)
+#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
+#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
+#define TKNQDEPTH_SHIFT 26
+#define TKNQDEPTHMSK (0x1F << TKNQDEPTH_SHIFT)
+
+ /* User HW Config3 Register (Read Only). Offset: 04Ch */
+ u32 ghwcfg3;
+#define DFIFO_DEPTH_SHIFT 16
+#define DFIFO_DEPTH ((u32)0xFFFF << DFIFO_DEPTH_SHIFT)
+ /* User HW Config4 Register (Read Only). Offset: 050h */
+ u32 ghwcfg4;
+#define NUM_DEV_PERIO_IN_EP_SHIFT 0
+#define NUM_DEV_PERIO_IN_EP (0xF << NUM_DEV_PERIO_IN_EP_SHIFT)
+#define DED_FIFO_EN (1 << 25)
+#define NUM_IN_EPS_SHIFT 26
+#define NUM_IN_EPS (0xF << NUM_IN_EPS_SHIFT)
+#define UTMI_PHY_DATA_WIDTH_SHIFT 14
+#define UTMI_PHY_DATA_WIDTH (0x3 << UTMI_PHY_DATA_WIDTH_SHIFT)
+ /* Reserved Offset: 054h-0FFh */
+ u32 reserved[43];
+ /* Host Periodic Transmit FIFO Size Register. Offset: 100h */
+ u32 hptxfsiz;
+
+ /*
+ * Device Periodic Transmit FIFO#n Register, if dedicated fifos are
+ * disabled. Otherwise Device Transmit FIFO#n Register.
+ *
+ * Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15)
+ */
+ u32 dptxfsiz_dieptxf[15];
+#define dwc_param_dev_tx_fifo_size_default 256
+#define dwc_param_dev_perio_tx_fifo_size_default 256
+};
+
+/*
+ * Device Global Registers. Offsets 800h-BFFh
+ *
+ * The following structures define the size and relative field offsets for the
+ * Device Mode Registers.
+ *
+ * These registers are visible only in Device mode and must not be accessed in
+ * Host mode, as the results are unknown.
+ */
+struct device_global_regs { /* CONFIG_DWC_OTG_REG_LE */
+ /* Device Configuration Register. Offset: 800h */
+ u32 dcfg;
+#define DWC_DCFG_FRAME_INTERVAL_80 0
+#define DWC_DCFG_FRAME_INTERVAL_85 1
+#define DWC_DCFG_FRAME_INTERVAL_90 2
+#define DWC_DCFG_FRAME_INTERVAL_95 3
+#define DWC_DCFG_FRAME_INTERVAL_MASK 3
+#define PERFRINT_SHIFT 11
+#define DEVSPDMSK (0x3 << 0)
+#define DEVADDR_SHIFT 4
+#define DEVADDRMSK (0x7F << DEVADDR_SHIFT)
+#define NZSTSOUTHSHK (1 << 2)
+ /* Device Control Register. Offset: 804h */
+ u32 dctl;
+#define RMTWKUPSIG (1 << 0)
+#define SFTDISCON (1 << 1)
+#define CGNPINNAK (1 << 7)
+ /* Device Status Register (Read Only). Offset: 808h */
+ u32 dsts;
+#define ENUMSPD_SHIFT 1
+#define ENUMSPDMSK (3 << ENUMSPD_SHIFT)
+#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
+#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
+#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2
+#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3
+ /* Reserved. Offset: 80Ch */
+ u32 unused;
+ /* Device IN Endpoint Common Interrupt Mask Register. Offset: 810h */
+ u32 diepmsk;
+#define TIMEOUTMSK (1 << 3)
+#define INTKNTXFEMP (1 << 4)
+#define INTKNEPMISMSK (1 << 5)
+#define INEPNAKEFFMSK (1 << 6)
+#define TXFIFOUNDRN (1 << 8)
+ /* Device OUT Endpoint Common Interrupt Mask Register. Offset: 814h */
+ u32 doepmsk;
+#define XFERCOMPLMSK (1 << 0)
+#define EPDISABLEDMSK (1 << 1)
+#define AHBERRMSK (1 << 2)
+#define SETUPMSK (1 << 3)
+#define INTKNTXFEMPMSK (1 << 4)
+ /* Device All Endpoints Interrupt Register. Offset: 818h */
+ u32 daint;
+ /* Device All Endpoints Interrupt Mask Register. Offset: 81Ch */
+ u32 daintmsk;
+#define DAINTMASK_IN_SHIFT 0
+#define DAINTMASK_OUT_SHIFT 16
+ /* Device IN Token Queue Read Register-1 (Read Only). Offset: 820h */
+ u32 dtknqr1;
+#define EPTK0_5_SHIFT 8
+#define EPTK0_5MSK ((u32)0xFFFFFF << EPTK0_5_SHIFT)
+#define INTKNWPTR_SHIFT 0
+#define INTKNWPTRMSK ((u32)0x1F << INTKNWPTR_SHIFT)
+ /* Device IN Token Queue Read Register-2 (Read Only). Offset: 824h */
+ u32 dtknqr2;
+ /* Device VBUS discharge Register. Offset: 828h */
+ u32 dvbusdis;
+ /* Device VBUS Pulse Register. Offset: 82Ch */
+ u32 dvbuspulse;
+ /* Device IN Token Queue Read Register-3 (Read Only). Offset: 830h */
+ u32 dtknqr3_dthrctl;
+ /* Device IN Token Queue Read Register-4 (Read Only). Offset: 834h */
+ u32 dtknqr4_fifoemptymsk;
+};
+/*
+ * Device Logical IN Endpoint-Specific Registers. Offsets 900h-AFCh
+ *
+ * There will be one set of endpoint registers per logical endpoint implemented.
+ *
+ * These registers are visible only in Device mode and must not be accessed in
+ * Host mode, as the results are unknown.
+ */
+struct device_in_ep_regs {
+ /*
+ * Device IN Endpoint Control Register.
+ * Offset:900h + (ep_num * 20h) + 00h
+ */
+ u32 diepctl;
+#define EPENA ((u32)1 << 31)
+#define EPDIS (1 << 30)
+#define SNAK (1 << 27)
+#define CNAK (1 << 26)
+#define SSTALL (1 << 21)
+#define MPS_SHIFT 0
+#define MPSMSK0 (3 << MPS_SHIFT)
+#define DWC_DEP0CTL_MPS_64 0
+#define DWC_DEP0CTL_MPS_32 1
+#define DWC_DEP0CTL_MPS_16 2
+#define DWC_DEP0CTL_MPS_8 3
+#define DIEPCTL_MPSMSK (0x7FF << MPS_SHIFT)
+ /* Reserved. Offset:900h + (ep_num * 20h) + 04h */
+ u32 reserved04;
+ /*
+ * Device IN Endpoint Interrupt Register.
+ * Offset:900h + (ep_num * 20h) + 08h
+ */
+ u32 diepint;
+#define TXFEMP (1 << 7)
+#define INTKNTXFEMP (1 << 4)
+#define XFERCOMPL (1 << 0)
+ /* Reserved. Offset:900h + (ep_num * 20h) + 0Ch */
+ u32 reserved0C;
+ /* Device IN Endpoint Transfer Size Register.
+ * Offset:900h + (ep_num * 20h) + 10h
+ */
+ u32 dieptsiz;
+#define PKTCNT_SHIFT 19
+ /*
+ * Device IN Endpoint DMA Address Register.
+ * Offset:900h + (ep_num * 20h) + 14h
+ */
+ u32 diepdma;
+ /* Reserved.
+ * Offset:900h + (ep_num * 20h) + 18h - 900h + (ep_num * 20h) + 1Ch
+ */
+ u32 dtxfsts;
+ /*
+ * Reserved.
+ * Offset:900h + (ep_num * 20h) + 1Ch - 900h + (ep_num * 20h) + 1Ch
+ */
+ u32 reserved18;
+};
+
+/*
+ * Device Logical OUT Endpoint-Specific Registers. Offsets: B00h-CFCh
+ *
+ * There will be one set of endpoint registers per logical endpoint implemented.
+ *
+ * These registers are visible only in Device mode and must not be accessed in
+ * Host mode, as the results are unknown.
+ */
+struct device_out_ep_regs {
+ /*
+ * Device OUT Endpoint Control Register.
+ * Offset:B00h + (ep_num * 20h) + 00h
+ */
+ u32 doepctl;
+#define DOEPCTL_MPSMSK 0x7FF
+#define USBACTEP (1 << 15)
+#define EPTYPE_SHIFT 18
+#define EPTYPEMSK (0x3 << EPTYPE_SHIFT)
+#define EPTYPE_BULK 0x2
+#define EPTYPE_INT 0x3
+#define DATA0PID (1 << 28)
+#define DATA1PID (1 << 29)
+#define DPIDMSK (1 << 16)
+ /*
+ * Device OUT Endpoint Frame number Register.
+ * Offset: B00h + (ep_num * 20h) + 04h
+ */
+ u32 doepfn;
+ /*
+ * Device OUT Endpoint Interrupt Register.
+ * Offset:B00h + (ep_num * 20h) + 08h
+ */
+ u32 doepint;
+#define XFERCOMPL (1 << 0)
+#define EPDISBLD (1 << 1)
+#define AHBERR (1 << 2)
+#define SETUP (1 << 3)
+ /* Reserved. Offset:B00h + (ep_num * 20h) + 0Ch */
+ u32 reserved0C;
+ /*
+ * Device OUT Endpoint Transfer Size Register.
+ * Offset: B00h + (ep_num * 20h) + 10h
+ */
+ u32 doeptsiz;
+#define XFERSIZE_SHIFT 0
+#define XFERSIZEMSK 0x3F
+#define PKTCNT_SHIFT 19
+#define PKTCNT (3 << 19)
+#define SUPCNT_SHIFT 29
+#define SUPCNTMSK (3 << SUPCNT_SHIFT)
+ /*
+ * Device OUT Endpoint DMA Address Register.
+ * Offset:B00h + (ep_num * 20h) + 14h
+ */
+ u32 doepdma;
+ /*
+ * Reserved.
+ * Offset:B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch
+ */
+ u32 unused[2];
+};
+#define MAX_EPS_CHANNELS 4
+
+/*
+ * The dwc_ep structure represents the state of a single endpoint when acting in
+ * device mode. It contains the data items needed for an endpoint to be
+ * activated and transfer packets.
+ */
+struct dwc_ep {
+ /* EP number used for register address lookup */
+ u8 num;
+ /* EP direction 0 = OUT */
+#if 0
+ u8 is_in;
+#endif
+ /* pointer to the transfer buffer */
+ u8 *xfer_buff;
+ /* Number of bytes to transfer */
+ u32 xfer_len;
+};
+
+/*
+ * DWC_otg PCD Structure.
+ * This structure encapsulates the data for the dwc_otg PCD.
+ */
+struct dwc_pcd {
+#if 0
+ /* USB gadget */
+ /* Current configuration */
+ u8 configuration;
+ /* Current interface */
+ u8 interface;
+ /* Current alternate settinng */
+ u8 alternate;
+ /* Current Address */
+ u16 address;
+ /* device state */
+/* usb_device_state_t device_state; */ /* current USB Device state */
+ /*
+ * SETUP packet for EP0. This structure is allocated as a DMA buffer on
+ * PCD initialization with enough space for up to 3 setup packets.
+ */
+#endif
+ struct usb_device_request *req;
+ /* Array of EPs. */
+ struct dwc_ep ep0;
+ /* Array of IN EPs. */
+ struct dwc_ep in_ep[MAX_EPS_CHANNELS];
+ /* Array of OUT EPs. */
+ struct dwc_ep out_ep[MAX_EPS_CHANNELS];
+};
+
+/*
+ * The device_if structure contains information needed to manage the DWC_otg
+ * controller acting in device mode. It represents the programming view of the
+ * device-specific aspects of the controller.
+ */
+struct device_if {
+ struct core_global_regs *core_global_regs;
+ /* Common configuration information */
+
+ /* Device Global Registers starting at offset 800h */
+ struct device_global_regs *dev_global_regs;
+#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
+
+ /* Device Logical IN Endpoint-Specific Registers 900h-AFCh */
+ struct device_in_ep_regs *in_ep_regs[MAX_EPS_CHANNELS];
+#define DWC_DEV_IN_EP_REG_OFFSET 0x900
+#define DWC_EP_REG_OFFSET 0x20
+
+ /* Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
+ struct device_out_ep_regs *out_ep_regs[MAX_EPS_CHANNELS];
+#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
+
+ /* Push/pop addresses for endpoints or host channels.*/
+ u32 *data_fifo[MAX_EPS_CHANNELS];
+#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
+#define DWC_OTG_DATA_FIFO_SIZE 0x1000
+
+ struct dwc_pcd pcd;
+ int speed;
+};
+
+
+/* Function declarations */
+
+void phy_init(void);
+void udc_irq(void);
+
+void udc_set_nak(int epid);
+void udc_unset_nak(int epid);
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
+int udc_init(void);
+/* void udc_enable(struct usb_device_instance *device);*/
+void udc_connect(void);
+void udc_disconnect(void);
+void udc_startup_events(struct usb_device_instance *device);
+void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
+ struct usb_endpoint_instance *endpoint);
+void udc_set_configuration_controller(u32);
+void udc_set_address_controller(u32);
+
+#endif /* __DW_UDC_H */
--
1.7.2.2
2
6
Hi all,
While looking into some trouble booting the latest Linux kernel patches
for i.MX6 display support, I found that the kernel driver was thrown off by
the interrupt status bits in the i.MX6 IPU.
Until and unless we have the ability to hand off a 'live' display, it seems
that we should disable the video driver as a part of the 'bootm' process.
At the very least, doing this will avoid the possibility of trash on the
display during the transition.
I've been looking, and I don't see a place to tap into this process.
It seems that having a shutdown routine for the display drivers
(cfb_console?) is the way to go.
Anybody know if I'm overlooking something?
Please advise,
Eric
8
32
Add i2c write command to write data from memory to i2c devices.
Signed-off-by: York Sun <yorksun(a)freescale.com>
---
common/cmd_i2c.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index 2cdc4ed..6099115 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -223,6 +223,54 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
return 0;
}
+static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ u_char chip;
+ uint devaddr, alen, length;
+ u_char *memaddr;
+
+ if (argc != 5)
+ return cmd_usage(cmdtp);
+
+ /*
+ * memaddr is the address where to store things in memory
+ */
+ memaddr = (u_char *)simple_strtoul(argv[1], NULL, 16);
+
+ /*
+ * I2C chip address
+ */
+ chip = simple_strtoul(argv[2], NULL, 16);
+
+ /*
+ * I2C data address within the chip. This can be 1 or
+ * 2 bytes long. Some day it might be 3 bytes long :-).
+ */
+ devaddr = simple_strtoul(argv[3], NULL, 16);
+ alen = get_alen(argv[3]);
+ if (alen > 3)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Length is the number of objects, not number of bytes.
+ */
+ length = simple_strtoul(argv[4], NULL, 16);
+
+ while (length-- > 0) {
+ if (i2c_write(chip, devaddr++, alen, memaddr++, 1) != 0) {
+ puts("Error writing to the chip.\n");
+ return 1;
+ }
+/*
+ * No write delay with FRAM devices.
+ */
+#if !defined(CONFIG_SYS_I2C_FRAM)
+ udelay(11000);
+#endif
+ }
+ return 0;
+}
+
/*
* Syntax:
* i2c md {i2c_chip} {addr}{.0, .1, .2} {len}
@@ -1282,6 +1330,7 @@ static cmd_tbl_t cmd_i2c_sub[] = {
U_BOOT_CMD_MKENT(nm, 2, 1, do_i2c_nm, "", ""),
U_BOOT_CMD_MKENT(probe, 0, 1, do_i2c_probe, "", ""),
U_BOOT_CMD_MKENT(read, 5, 1, do_i2c_read, "", ""),
+ U_BOOT_CMD_MKENT(write, 5, 0, do_i2c_write, "", ""),
U_BOOT_CMD_MKENT(reset, 0, 1, do_i2c_reset, "", ""),
#if defined(CONFIG_CMD_SDRAM)
U_BOOT_CMD_MKENT(sdram, 1, 1, do_sdram, "", ""),
@@ -1333,6 +1382,7 @@ U_BOOT_CMD(
"i2c nm chip address[.0, .1, .2] - write to I2C device (constant address)\n"
"i2c probe - show devices on the I2C bus\n"
"i2c read chip address[.0, .1, .2] length memaddress - read to memory \n"
+ "i2c write memaddress chip address[.0, .1, .2] length - write memory to i2c\n"
"i2c reset - re-init the I2C Controller\n"
#if defined(CONFIG_CMD_SDRAM)
"i2c sdram chip - print SDRAM configuration information\n"
--
1.7.9.5
4
8
Hi, Iwamatsu-san
I managed to work i2c on KZM-A9-GT board. Now "i2c md" and "i2c mw" for i2c channel 0 work properly.
I think this modification is common for R-mobile, but I have SH73A0 document only. Iwamatu-san, plese review this.
This patch set is based on arm/rmobile branch of u-boot-sh.git.
Tetsuyuki Kobayashi (3):
i2c: sh_i2c.c: support iccl and icch extension
i2c: sh_i2c.c: correct BUSY bit define in ICSR
i2c: sh_i2c.c: adjust for SH73A0
drivers/i2c/sh_i2c.c | 38 +++++++++++++++++++++++++++++---------
include/configs/kzm9g.h | 2 +-
2 files changed, 30 insertions(+), 10 deletions(-)
--
1.7.9.5
3
48

[U-Boot] [PATCH - resend due to bounce] libfdt: Add fdt functionality for more intuitive
by Peter Feuerer 16 Oct '12
by Peter Feuerer 16 Oct '12
16 Oct '12
libfdt: Add fdt functionality for more intuitive fdt handling
New functions:
fdt_read - retrieve the value of a property by full path
fdt_write - create or change a property with full path and create subnodes if needed
fdt_create_path - create subnode path with parents
Signed-off-by: Peter Feuerer <peter.feuerer(a)sysgo.com>
CC: David Gibson <david(a)gibson.dropbear.id.au>
CC: Gerald Van Baren <gvb(a)unssw.com>
---
include/libfdt.h | 93 ++++++++++++++++++++++++++++++++++++++++
lib/libfdt/fdt_ro.c | 30 +++++++++++++
lib/libfdt/fdt_rw.c | 97 ++++++++++++++++++++++++++++++++++++++++++
lib/libfdt/libfdt_internal.h | 4 ++
4 files changed, 224 insertions(+), 0 deletions(-)
diff --git a/include/libfdt.h b/include/libfdt.h
index de82ed5..822ab18 100644
--- a/include/libfdt.h
+++ b/include/libfdt.h
@@ -548,6 +548,37 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
}
/**
+ * fdt_read - retrieve the value of a property by full path
+ * @fdt: pointer to the device tree blob
+ * @path: string containing the absolute path of the property
+ * @name: name of the property
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADPATH,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_read(const void *fdt, const char *path,
+ const char *name, int *lenp);
+
+/**
* fdt_get_phandle - retrieve the phandle of a given node
* @fdt: pointer to the device tree blob
* @nodeoffset: structure block offset of the node
@@ -1066,6 +1097,38 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name);
*/
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len);
+/**
+ * fdt_write - create or change a property with full path and create
+ * all subnodes to the property if needed
+ * @fdt: pointer to the device tree blob
+ * @path: string containing the absolute path of the property
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_write() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist. Additionally it creates all parent nodes if
+ * not yet existing.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_write(void *fdt, const char *path, const char *name,
+ const void *val, int len);
/**
* fdt_setprop_cell - set a property to a single cell value
@@ -1204,6 +1267,36 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
/**
+ * fdt_create_path - create subnode path with parents
+ * @fdt: pointer to the device tree blob
+ * @path: absolute path of subnodes to create
+ *
+ * fdt_create_path() creates absolute subnode path with all needed
+ * parents, if they don't exist.
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * structure block offset of the created nodeequested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ * the given name
+ * -FDT_ERR_NOSPACE, if there is insufficient free space in the
+ * blob to contain the new node
+ * -FDT_ERR_NOSPACE,
+ * -FDT_ERR_BADPATH,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_create_path(struct fdt_header *fdt, const char *path);
+
+/**
* fdt_del_node - delete a node (subtree)
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node to nop
diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c
index 1933010..9a08200 100644
--- a/lib/libfdt/fdt_ro.c
+++ b/lib/libfdt/fdt_ro.c
@@ -324,6 +324,36 @@ const void *fdt_getprop(const void *fdt, int nodeoffset,
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
}
+const void *fdt_read(const void *fdt, const char *path,
+ const char *name, int *lenp)
+{
+ int nodeoffset;
+ int len;
+ const void *nodep ;
+
+ if (fdt_check_header(fdt) != 0) {
+ if (lenp)
+ *lenp = -FDT_ERR_BADSTRUCTURE;
+ return NULL;
+ }
+
+ nodeoffset = fdt_path_offset(fdt, path);
+
+ if (nodeoffset < 0) {
+ if (lenp)
+ *lenp = -FDT_ERR_BADPATH;
+ return NULL;
+ } else {
+ nodep = fdt_getprop(fdt, nodeoffset, name, &len);
+ if (len <= 0)
+ return NULL;
+ if (lenp)
+ *lenp = len;
+ }
+ return nodep;
+}
+
+
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
{
const uint32_t *php;
diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c
index 5c27a67..ccebafb 100644
--- a/lib/libfdt/fdt_rw.c
+++ b/lib/libfdt/fdt_rw.c
@@ -293,6 +293,21 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
return 0;
}
+int fdt_write(void *fdt, const char *path, const char *name,
+ const void *val, int len)
+{
+ int nodeoffset;
+
+ FDT_CHECK_HEADER(fdt);
+
+ nodeoffset = fdt_create_path(fdt, path);
+
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ return fdt_setprop(fdt, nodeoffset, name, val, len);
+}
+
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
@@ -354,6 +369,88 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
}
+int fdt_create_path_internal(struct fdt_header *fdt, char *path)
+{
+ int offset = 0;
+ char *p = NULL;
+ char *last_slash = NULL;
+ char *path2 = path;
+ int ret = 0;
+
+ /* search for last slash */
+ for (p = path; *p != 0; ++p)
+ if (*p == '/')
+ last_slash = p;
+
+ /* if path ends with "/" then, error */
+ if (*(last_slash + 1) == 0)
+ return -FDT_ERR_BADPATH;
+
+ /*
+ * if last_slash is root, use "/" instead of string
+ * otherwise terminate string at slash
+ */
+ if (last_slash == path)
+ path2 = "/";
+ else
+ *last_slash = 0;
+
+ /*
+ * test if the parent path is valid, if not valid,
+ * recursively add paths
+ */
+ offset = fdt_path_offset(fdt, path2);
+ if (offset == -FDT_ERR_NOTFOUND)
+ offset = fdt_create_path_internal(fdt, path2);
+
+ if (offset < 0)
+ return offset;
+
+ /* path valid, create subnode */
+ ret = fdt_add_subnode(fdt, offset, last_slash + 1);
+
+ /* undo termination */
+ if (last_slash && last_slash != path)
+ *last_slash = '/';
+
+ return ret;
+}
+
+int fdt_create_path(struct fdt_header *fdt, const char *path)
+{
+ int offset = 0;
+ int ret = 0;
+ int size = 0;
+#ifndef FDT_USE_MALLOC
+ char path_mem[FDT_MAX_PATHLEN] = {0};
+ size = FDT_MAX_PATHLEN;
+#else
+ char *path_mem;
+ size = strlen(path);
+ path_mem = calloc(size, 1);
+ if (!path_mem)
+ return -FDT_ERR_NOSPACE;
+#endif
+
+ /* if full path already exists, return the offset */
+ offset = fdt_path_offset(fdt, path);
+ if (offset >= 0) {
+ ret = offset;
+ goto end;
+ }
+
+ /* copy path to local path variable, so that we can modify it */
+ strncpy(path_mem, path, size - 1);
+
+ ret = fdt_create_path_internal(fdt, path_mem);
+end:
+#ifdef FDT_USE_MALLOC
+ free(path_mem);
+#endif
+ return ret;
+
+}
+
int fdt_del_node(void *fdt, int nodeoffset)
{
int endoffset;
diff --git a/lib/libfdt/libfdt_internal.h b/lib/libfdt/libfdt_internal.h
index 381133b..786a052 100644
--- a/lib/libfdt/libfdt_internal.h
+++ b/lib/libfdt/libfdt_internal.h
@@ -55,6 +55,10 @@
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
+#ifndef FDT_USE_MALLOC
+#define FDT_MAX_PATHLEN 2048
+#endif
+
#define FDT_CHECK_HEADER(fdt) \
{ \
int err; \
--
1.7.3
2
1

16 Oct '12
Changes from previous:
- Changed // to /* */
- Ran through checkpatch.pl, cleaned up a number of line-too-big and
extra space in the code that was shifted due to being in the new 'if'.
Thanks,
csd
Subject: [PATCH] Add support for MMC to fw_printenv/setenv
This patch checks if the fd is MTD and if not (using an MTD-specific IOCTL)
and skips the flash unlock/erase/lock sequence if it is not MTD.
- fd_is_mtd function added to determine MTD/MMC
- flash_write_block made to not try MTD operations if mtd_type == MTD_ABSENT
- flash_read works with MMC devices now.
Signed-off-by: Christian Daudt <csd(a)broadcom.com>
---
tools/env/fw_env.c | 103 ++++++++++++++++++++++++++++++++++++----------------
1 files changed, 71 insertions(+), 32 deletions(-)
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 996682e..c760429 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -211,6 +211,27 @@ static int flash_io (int mode);
static char *envmatch (char * s1, char * s2);
static int parse_config (void);
+
+/*
+ * Returns 1 if it is MTD and 0 if it is not MTD
+ */
+static int fd_is_mtd(int fd)
+{
+ struct mtd_info_user mtdinfo;
+ int rc;
+
+ rc = ioctl(fd, MEMGETINFO, &mtdinfo);
+ if (rc < 0) {
+ /* Failed MEMGETINFO, not MTD */
+ return 0;
+ } else {
+ /* Succeeded, MTD */
+ return 1;
+ }
+}
+
+
+
#if defined(CONFIG_FILE)
static int get_config (char *);
#endif
@@ -836,31 +857,35 @@ static int flash_write_buf (int dev, int fd,
void *buf, size_t count,
/* This only runs once on NOR flash and SPI-dataflash */
while (processed < write_total) {
- rc = flash_bad_block (fd, mtd_type, &blockstart);
- if (rc < 0) /* block test failed */
- return rc;
+ if (mtd_type != MTD_ABSENT) {
+ rc = flash_bad_block(fd, mtd_type, &blockstart);
+ if (rc < 0) /* block test failed */
+ return rc;
- if (blockstart + erasesize > top_of_range) {
- fprintf (stderr, "End of range reached, aborting\n");
- return -1;
- }
+ if (blockstart + erasesize > top_of_range) {
+ fprintf(stderr,
+ "End of range reached, aborting\n");
+ return -1;
+ }
- if (rc) { /* block is bad */
- blockstart += blocklen;
- continue;
- }
+ if (rc) { /* block is bad */
+ blockstart += blocklen;
+ continue;
+ }
- erase.start = blockstart;
- ioctl (fd, MEMUNLOCK, &erase);
+ erase.start = blockstart;
+ ioctl(fd, MEMUNLOCK, &erase);
- /* Dataflash does not need an explicit erase cycle */
- if (mtd_type != MTD_DATAFLASH)
- if (ioctl (fd, MEMERASE, &erase) != 0) {
- fprintf (stderr, "MTD erase error on %s: %s\n",
- DEVNAME (dev),
- strerror (errno));
- return -1;
- }
+ /* Dataflash does not need an explicit erase cycle */
+ if (mtd_type != MTD_DATAFLASH)
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ fprintf(stderr,
+ "MTD erase error on %s: %s\n",
+ DEVNAME(dev),
+ strerror(errno));
+ return -1;
+ }
+ }
if (lseek (fd, blockstart, SEEK_SET) == -1) {
fprintf (stderr,
@@ -878,7 +903,8 @@ static int flash_write_buf (int dev, int fd, void
*buf, size_t count,
return -1;
}
- ioctl (fd, MEMLOCK, &erase);
+ if (mtd_type != MTD_ABSENT)
+ ioctl(fd, MEMLOCK, &erase);
processed += blocklen;
block_seek = 0;
@@ -964,18 +990,31 @@ static int flash_read (int fd)
{
struct mtd_info_user mtdinfo;
int rc;
+ int is_mtd;
- rc = ioctl (fd, MEMGETINFO, &mtdinfo);
- if (rc < 0) {
- perror ("Cannot get MTD information");
- return -1;
- }
+ is_mtd = fd_is_mtd(fd);
- if (mtdinfo.type != MTD_NORFLASH &&
- mtdinfo.type != MTD_NANDFLASH &&
- mtdinfo.type != MTD_DATAFLASH) {
- fprintf (stderr, "Unsupported flash type %u\n", mtdinfo.type);
- return -1;
+ if (is_mtd) {
+ rc = ioctl(fd, MEMGETINFO, &mtdinfo);
+ if (rc < 0) {
+ perror("Cannot get MTD information");
+ return -1;
+ }
+
+ if (mtdinfo.type != MTD_NORFLASH &&
+ mtdinfo.type != MTD_NANDFLASH &&
+ mtdinfo.type != MTD_DATAFLASH) {
+ fprintf(stderr, "Unsupported flash type %u\n",
+ mtdinfo.type);
+ return -1;
+ }
+ } else {
+ /*
+ * Kinda hacky assuming !MTD means == MMC
+ * but seems to be the easiest way to
+ * determine that.
+ */
+ mtdinfo.type = MTD_ABSENT;
}
DEVTYPE(dev_current) = mtdinfo.type;
--
1.7.1
3
3

16 Oct '12
Built u-boot elf file does not contain any dwarf informations by default. This
information is required for debugging.
Add dwarf ver 2 flag in DBGFLAGS.
Signed-off-by: Radu Lazarescu <radu.lazarescu(a)freescale.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar(a)freescale.com>
---
Applies on http://git.denx.de/u-boot.git branch master
config.mk | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/config.mk b/config.mk
index ddaa477..11bc20d 100644
--- a/config.mk
+++ b/config.mk
@@ -178,7 +178,7 @@ endif
# who are porting old code to latest mainline but not updating $(AR).
ARFLAGS = $(error update your Makefile to use cmd_link_o_target and not AR)
RELFLAGS= $(PLATFORM_RELFLAGS)
-DBGFLAGS= -g # -DDEBUG
+DBGFLAGS= -g -gdwarf-2 # -DDEBUG
OPTFLAGS= -Os #-fomit-frame-pointer
OBJCFLAGS += --gap-fill=0xff
--
1.7.5.4
4
5

[U-Boot] [PATCH 1/2] mmc: pxa: Flip over the remaining boards to pxa_mmc_generic
by Marek Vasut 15 Oct '12
by Marek Vasut 15 Oct '12
15 Oct '12
Some of the boards still used the old PXA_MMC driver instead of the
new generic one. Use the new one instead so the old can be removed
and the generic MMC framework can be properly used.
Signed-off-by: Marek Vasut <marex(a)denx.de>
Cc: Andy Fleming <afleming(a)freescale.com>
---
board/lubbock/lubbock.c | 9 +++++++++
board/palmtc/palmtc.c | 9 +++++++++
board/pxa255_idp/pxa_idp.c | 9 +++++++++
board/trizepsiv/conxs.c | 9 +++++++++
include/configs/lubbock.h | 3 ++-
include/configs/palmtc.h | 3 ++-
include/configs/pxa255_idp.h | 3 ++-
include/configs/trizepsiv.h | 3 ++-
8 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/board/lubbock/lubbock.c b/board/lubbock/lubbock.c
index 3527b38..ef2cc24 100644
--- a/board/lubbock/lubbock.c
+++ b/board/lubbock/lubbock.c
@@ -29,6 +29,7 @@
#include <netdev.h>
#include <asm/arch/pxa.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/regs-mmc.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -56,6 +57,14 @@ int board_init (void)
return 0;
}
+#ifdef CONFIG_CMD_MMC
+int board_mmc_init(bd_t *bis)
+{
+ pxa_mmc_register(0);
+ return 0;
+}
+#endif
+
int board_late_init(void)
{
setenv("stdout", "serial");
diff --git a/board/palmtc/palmtc.c b/board/palmtc/palmtc.c
index 4adf152..c850cf9 100644
--- a/board/palmtc/palmtc.c
+++ b/board/palmtc/palmtc.c
@@ -24,6 +24,7 @@
#include <serial.h>
#include <asm/io.h>
#include <asm/arch/pxa.h>
+#include <asm/arch/regs-mmc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -51,6 +52,14 @@ int board_init(void)
return 0;
}
+#ifdef CONFIG_CMD_MMC
+int board_mmc_init(bd_t *bis)
+{
+ pxa_mmc_register(0);
+ return 0;
+}
+#endif
+
struct serial_device *default_serial_console(void)
{
return &serial_ffuart_device;
diff --git a/board/pxa255_idp/pxa_idp.c b/board/pxa255_idp/pxa_idp.c
index 877e8d9..9931efd 100644
--- a/board/pxa255_idp/pxa_idp.c
+++ b/board/pxa255_idp/pxa_idp.c
@@ -35,6 +35,7 @@
#include <command.h>
#include <asm/io.h>
#include <asm/arch/pxa.h>
+#include <asm/arch/regs-mmc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -77,6 +78,14 @@ int board_init (void)
return 0;
}
+#ifdef CONFIG_CMD_MMC
+int board_mmc_init(bd_t *bis)
+{
+ pxa_mmc_register(0);
+ return 0;
+}
+#endif
+
int board_late_init(void)
{
setenv("stdout", "serial");
diff --git a/board/trizepsiv/conxs.c b/board/trizepsiv/conxs.c
index 1291195..af6fe25 100644
--- a/board/trizepsiv/conxs.c
+++ b/board/trizepsiv/conxs.c
@@ -34,6 +34,7 @@
#include <common.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/pxa.h>
+#include <asm/arch/regs-mmc.h>
#include <netdev.h>
#include <asm/io.h>
@@ -159,3 +160,11 @@ int board_eth_init(bd_t *bis)
return dm9000_initialize(bis);
}
#endif
+
+#ifdef CONFIG_CMD_MMC
+int board_mmc_init(bd_t *bis)
+{
+ pxa_mmc_register(0);
+ return 0;
+}
+#endif
diff --git a/include/configs/lubbock.h b/include/configs/lubbock.h
index 0a1d1e0..59515f5 100644
--- a/include/configs/lubbock.h
+++ b/include/configs/lubbock.h
@@ -129,7 +129,8 @@
#define CONFIG_SYS_CPUSPEED 0x161 /* set core clock to 400/200/100 MHz */
#ifdef CONFIG_MMC
-#define CONFIG_PXA_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_PXA_MMC_GENERIC
#define CONFIG_CMD_MMC
#define CONFIG_SYS_MMC_BASE 0xF0000000
#endif
diff --git a/include/configs/palmtc.h b/include/configs/palmtc.h
index bc88354..699b39f 100644
--- a/include/configs/palmtc.h
+++ b/include/configs/palmtc.h
@@ -76,7 +76,8 @@
*/
#ifdef CONFIG_CMD_MMC
#define CONFIG_MMC
-#define CONFIG_PXA_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_PXA_MMC_GENERIC
#define CONFIG_SYS_MMC_BASE 0xF0000000
#define CONFIG_CMD_FAT
#define CONFIG_CMD_EXT2
diff --git a/include/configs/pxa255_idp.h b/include/configs/pxa255_idp.h
index ce9e7d1..d0d88c8 100644
--- a/include/configs/pxa255_idp.h
+++ b/include/configs/pxa255_idp.h
@@ -244,7 +244,8 @@
#define RTC 1 /* enable 32KHz osc */
#ifdef CONFIG_MMC
-#define CONFIG_PXA_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_PXA_MMC_GENERIC
#define CONFIG_CMD_MMC
#define CONFIG_SYS_MMC_BASE 0xF0000000
#endif
diff --git a/include/configs/trizepsiv.h b/include/configs/trizepsiv.h
index 151059a..52bc973 100644
--- a/include/configs/trizepsiv.h
+++ b/include/configs/trizepsiv.h
@@ -170,7 +170,8 @@
#define CONFIG_SYS_CPUSPEED 0x207 /* need to look more closely, I think this is Turbo = 2x, L=91Mhz */
#ifdef CONFIG_MMC
-#define CONFIG_PXA_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_PXA_MMC_GENERIC
#define CONFIG_CMD_MMC
#define CONFIG_SYS_MMC_BASE 0xF0000000
#endif
--
1.7.10.4
2
3

15 Oct '12
This patch is supported DesginWare MMC Controller.
Signed-off-by: Jaehoon Chung <jh80.chung(a)samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park(a)samsung.com>
Signed-off-by: Rajeshawari Shinde <rajeshwari.s(a)samsung.com>
---
drivers/mmc/dw_mmc.c | 400 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/dwmmc.h | 186 +++++++++++++++++++++++
2 files changed, 586 insertions(+), 0 deletions(-)
create mode 100644 drivers/mmc/dw_mmc.c
create mode 100644 include/dwmmc.h
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
new file mode 100644
index 0000000..e634e1d
--- /dev/null
+++ b/drivers/mmc/dw_mmc.c
@@ -0,0 +1,400 @@
+/*
+ * (C) Copyright 2012 SAMSUNG Electronics
+ * Jaehoon Chung <jh80.chung(a)samsung.com>
+ * Rajeshawari Shinde <rajeshwari.s(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ *
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <dwmmc.h>
+#include <asm/arch/clk.h>
+#include <asm-generic/errno.h>
+
+#define PAGE_SIZE 4096
+
+static int dwmci_wait_reset(struct dwmci_host *host, u32 value)
+{
+ unsigned long timeout = 1000;
+ u32 ctrl;
+
+ dwmci_writel(host, DWMCI_CTRL, value);
+
+ while (timeout--) {
+ ctrl = dwmci_readl(host, DWMCI_CTRL);
+ if (!(ctrl & DWMCI_RESET_ALL))
+ return 1;
+ if (timeout == 0)
+ break;
+ }
+ return 0;
+}
+
+static void dwmci_set_idma_desc(u8 *idmac, unsigned int des0,
+ unsigned int des1, unsigned int des2)
+{
+ struct dwmci_idmac *desc = (struct dwmci_idmac *)idmac;
+
+ desc->des0 = des0;
+ desc->des1 = des1;
+ desc->des2 = des2;
+ desc->des3 = (unsigned int)desc + sizeof(struct dwmci_idmac);
+}
+
+static void dwmci_prepare_data(struct dwmci_host *host,
+ struct mmc_data *data)
+{
+ unsigned long ctrl;
+ unsigned int i = 0, flag, cnt, blk_cnt;
+ struct dwmci_idmac *p;
+ ulong data_start, data_end, start_addr;
+ ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, idmac, 65565);
+
+
+ p = idmac;
+ blk_cnt = data->blocks;
+
+ dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET);
+
+ if (data->flags == MMC_DATA_READ)
+ start_addr = (unsigned int)data->dest;
+ else
+ start_addr = (unsigned int)data->src;
+
+ do {
+ flag = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ;
+ flag |= (i == 0) ? DWMCI_IDMAC_FS : 0;
+ if (blk_cnt <= 8) {
+ flag |= DWMCI_IDMAC_LD;
+ cnt = data->blocksize * blk_cnt;
+ } else {
+ flag &= ~DWMCI_IDMAC_LD;
+ cnt = data->blocksize * 8;
+ }
+
+ dwmci_set_idma_desc((u8 *)p, flag, cnt,
+ start_addr + (i * PAGE_SIZE));
+
+ if (blk_cnt <= 8)
+ break;
+ blk_cnt -= 8;
+ p++;
+ i++;
+ } while(1);
+
+ data_start = (ulong)idmac;
+ data_end = (ulong)p;
+ flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN);
+
+ dwmci_writel(host, DWMCI_DBADDR, (unsigned int)(idmac));
+
+ ctrl = dwmci_readl(host, DWMCI_CTRL);
+ ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN;
+ dwmci_writel(host, DWMCI_CTRL, ctrl);
+
+ ctrl = dwmci_readl(host, DWMCI_BMOD);
+ ctrl |= DWMCI_BMOD_IDMAC_FB | DWMCI_BMOD_IDMAC_EN;
+ dwmci_writel(host, DWMCI_BMOD, ctrl);
+
+ dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize);
+ dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks);
+}
+
+static int dwmci_set_transfer_mode(struct dwmci_host *host,
+ struct mmc_data *data)
+{
+ unsigned long mode;
+
+ mode = DWMCI_CMD_DATA_EXP;
+ if (data->flags & MMC_DATA_WRITE)
+ mode |= DWMCI_CMD_RW;
+
+ return mode;
+}
+
+static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ struct dwmci_host *host = (struct dwmci_host *)mmc->priv;
+ int flags = 0, i;
+ unsigned int timeout = 100000;
+ u32 retry = 10000;
+ u32 mask, ctrl;
+
+ while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) {
+ if (timeout == 0) {
+ printf("Timeout on data busy\n");
+ return TIMEOUT;
+ }
+ timeout--;
+ }
+
+ dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);
+
+ if (data)
+ dwmci_prepare_data(host, data);
+
+
+ dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);
+
+ if (data) {
+ flags = dwmci_set_transfer_mode(host, data);
+ }
+
+ if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY))
+ return -1;
+
+ if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+ flags |= DWMCI_CMD_ABORT_STOP;
+ else
+ flags |= DWMCI_CMD_PRV_DAT_WAIT;
+
+ if (cmd->resp_type & MMC_RSP_PRESENT) {
+ flags |= DWMCI_CMD_RESP_EXP;
+ if (cmd->resp_type & MMC_RSP_136)
+ flags |= DWMCI_CMD_RESP_LENGTH;
+ }
+
+ if (cmd->resp_type & MMC_RSP_CRC)
+ flags |= DWMCI_CMD_CHECK_CRC;
+
+ flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG);
+
+ debug("Sending CMD%d\n",cmd->cmdidx);
+
+ dwmci_writel(host, DWMCI_CMD, flags);
+
+ for (i = 0; i < retry; i++) {
+ mask = dwmci_readl(host, DWMCI_RINTSTS);
+ if (mask & DWMCI_INTMSK_CDONE) {
+ if (!data)
+ dwmci_writel(host, DWMCI_RINTSTS, mask);
+ break;
+ }
+ }
+
+ if (i == retry)
+ return TIMEOUT;
+
+ if (mask & DWMCI_INTMSK_RTO) {
+ debug("Response Timeout..\n");
+ return TIMEOUT;
+ } else if (mask & DWMCI_INTMSK_RE) {
+ debug("Response Error..\n");
+ return -1;
+ }
+
+
+ if (cmd->resp_type & MMC_RSP_PRESENT) {
+ if (cmd->resp_type & MMC_RSP_136) {
+ cmd->response[0] = dwmci_readl(host, DWMCI_RESP3);
+ cmd->response[1] = dwmci_readl(host, DWMCI_RESP2);
+ cmd->response[2] = dwmci_readl(host, DWMCI_RESP1);
+ cmd->response[3] = dwmci_readl(host, DWMCI_RESP0);
+ } else {
+ cmd->response[0] = dwmci_readl(host, DWMCI_RESP0);
+ }
+ }
+
+ if (data) {
+ while (1) {
+ mask = dwmci_readl(host, DWMCI_RINTSTS);
+ if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) {
+ debug("DATA ERROR!\n");
+ return -1;
+ } else if (mask & DWMCI_INTMSK_DTO)
+ break;
+ }
+
+ dwmci_writel(host, DWMCI_RINTSTS, mask);
+
+ ctrl = dwmci_readl(host, DWMCI_CTRL);
+ ctrl &= ~(DWMCI_DMA_EN);
+ dwmci_writel(host, DWMCI_CTRL, ctrl);
+ }
+
+ udelay(100);
+
+ return 0;
+}
+
+static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
+{
+ u32 div, status;
+ int timeout = 10000;
+ unsigned long sclk;
+
+ if (freq == host->clock)
+ return 0;
+
+ /*
+ * If host->mmc_clk didn't define,
+ * then assume that host->bus_hz is source clock value.
+ * host->bus_hz should be set from user.
+ */
+ if (host->mmc_clk)
+ sclk = host->mmc_clk(host->dev_index);
+ else if (host->bus_hz)
+ sclk = host->bus_hz;
+ else {
+ printf("Didn't get source clock value..\n");
+ return -EINVAL;
+ }
+
+ for (div = 1; div < 255; div++) {
+ if ((sclk / (2 * div)) <= freq) {
+ break;
+ }
+ }
+
+ dwmci_writel(host, DWMCI_CLKENA, 0);
+ dwmci_writel(host, DWMCI_CLKSRC, 0);
+
+ dwmci_writel(host, DWMCI_CLKDIV, div);
+ dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT |
+ DWMCI_CMD_UPD_CLK | DWMCI_CMD_START);
+
+ do {
+ status = dwmci_readl(host, DWMCI_CMD);
+ if (timeout == 0) {
+ printf("TIMEOUT error!!\n");
+ return -ETIMEDOUT;
+ }
+ } while ((status & DWMCI_CMD_START) && timeout--);
+
+ dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE |
+ DWMCI_CLKEN_LOW_PWR);
+
+ dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT |
+ DWMCI_CMD_UPD_CLK | DWMCI_CMD_START);
+
+ timeout = 10000;
+ do {
+ status = dwmci_readl(host, DWMCI_CMD);
+ if (timeout == 0) {
+ printf("TIMEOUT error!!\n");
+ return -ETIMEDOUT;
+ }
+ } while ((status & DWMCI_CMD_START) && timeout--);
+
+ host->clock = freq;
+
+ return 0;
+}
+
+static void dwmci_set_ios(struct mmc *mmc)
+{
+ struct dwmci_host *host = (struct dwmci_host *)mmc->priv;
+ u32 ctype;
+
+ debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock);
+
+ dwmci_setup_bus(host, mmc->clock);
+ switch (mmc->bus_width) {
+ case 8:
+ ctype = DWMCI_CTYPE_8BIT;
+ break;
+ case 4:
+ ctype = DWMCI_CTYPE_4BIT;
+ break;
+ default:
+ ctype = DWMCI_CTYPE_1BIT;
+ break;
+ }
+
+ dwmci_writel(host, DWMCI_CTYPE, ctype);
+
+ if (host->clksel)
+ host->clksel(host);
+}
+
+static int dwmci_init(struct mmc *mmc)
+{
+ struct dwmci_host *host = (struct dwmci_host *)mmc->priv;
+ u32 fifo_size, fifoth_val;
+
+ dwmci_writel(host, DWMCI_PWREN, 1);
+
+ if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) {
+ debug("%s[%d] Fail-reset!!\n",__func__,__LINE__);
+ return -1;
+ }
+
+ dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF);
+ dwmci_writel(host, DWMCI_INTMASK, 0);
+
+ dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF);
+
+ dwmci_writel(host, DWMCI_IDINTEN, 0);
+ dwmci_writel(host, DWMCI_BMOD, 1);
+
+ fifo_size = dwmci_readl(host, DWMCI_FIFOTH);
+ if (host->fifoth_val)
+ fifoth_val = host->fifoth_val;
+ else
+ fifoth_val = (0x2 << 28) | ((fifo_size/2 -1) << 16) |
+ ((fifo_size/2) << 0);
+ dwmci_writel(host, DWMCI_FIFOTH, fifoth_val);
+
+ dwmci_writel(host, DWMCI_CLKENA, 0);
+ dwmci_writel(host, DWMCI_CLKSRC, 0);
+
+ return 0;
+}
+
+int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk, int index)
+{
+ struct mmc *mmc;
+ int err = 0;
+
+ mmc = malloc(sizeof(struct mmc));
+ if (!mmc) {
+ printf("mmc malloc fail!\n");
+ return -1;
+ }
+
+ mmc->priv = host;
+ host->mmc = mmc;
+
+ sprintf(mmc->name, "%s", host->name);
+ mmc->send_cmd = dwmci_send_cmd;
+ mmc->set_ios = dwmci_set_ios;
+ mmc->init = dwmci_init;
+ mmc->f_min = min_clk;
+ mmc->f_max = max_clk;
+
+ mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+
+ if (host->caps)
+ mmc->host_caps = host->caps;
+ else
+ mmc->host_caps = 0;
+
+ if (host->buswidth == 8) {
+ mmc->host_caps |= MMC_MODE_8BIT;
+ mmc->host_caps &= ~MMC_MODE_4BIT;
+ } else {
+ mmc->host_caps |= MMC_MODE_4BIT;
+ mmc->host_caps &= ~MMC_MODE_8BIT;
+ }
+ mmc->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_HC;
+
+ err = mmc_register(mmc);
+
+ return err;
+}
diff --git a/include/dwmmc.h b/include/dwmmc.h
new file mode 100644
index 0000000..9648586
--- /dev/null
+++ b/include/dwmmc.h
@@ -0,0 +1,186 @@
+/*
+ * (C) Copyright 2012 SAMSUNG Electronics
+ * Jaehoon Chung <jh80.chung(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ *
+ */
+
+#ifndef __DWMMC_HW_H
+#define __DWMMC_HW_H
+
+#include <asm/io.h>
+#include <mmc.h>
+
+#define DWMCI_CTRL 0x000
+#define DWMCI_PWREN 0x004
+#define DWMCI_CLKDIV 0x008
+#define DWMCI_CLKSRC 0x00C
+#define DWMCI_CLKENA 0x010
+#define DWMCI_TMOUT 0x014
+#define DWMCI_CTYPE 0x018
+#define DWMCI_BLKSIZ 0x01C
+#define DWMCI_BYTCNT 0x020
+#define DWMCI_INTMASK 0x024
+#define DWMCI_CMDARG 0x028
+#define DWMCI_CMD 0x02C
+#define DWMCI_RESP0 0x030
+#define DWMCI_RESP1 0x034
+#define DWMCI_RESP2 0x038
+#define DWMCI_RESP3 0x03C
+#define DWMCI_MINTSTS 0x040
+#define DWMCI_RINTSTS 0x044
+#define DWMCI_STATUS 0x048
+#define DWMCI_FIFOTH 0x04C
+#define DWMCI_CDETECT 0x050
+#define DWMCI_WRTPRT 0x054
+#define DWMCI_GPIO 0x058
+#define DWMCI_TCMCNT 0x05C
+#define DWMCI_TBBCNT 0x060
+#define DWMCI_DEBNCE 0x064
+#define DWMCI_USRID 0x068
+#define DWMCI_VERID 0x06C
+#define DWMCI_HCON 0x070
+#define DWMCI_UHS_REG 0x074
+#define DWMCI_BMOD 0x080
+#define DWMCI_PLDMND 0x084
+#define DWMCI_DBADDR 0x088
+#define DWMCI_IDSTS 0x08C
+#define DWMCI_IDINTEN 0x090
+#define DWMCI_DSCADDR 0x094
+#define DWMCI_BUFADDR 0x098
+#define DWMCI_DATA 0x200
+
+/* Interrupt Mask register */
+#define DWMCI_INTMSK_ALL 0xffffffff
+#define DWMCI_INTMSK_RE (1 << 1)
+#define DWMCI_INTMSK_CDONE (1 << 2)
+#define DWMCI_INTMSK_DTO (1 << 3)
+#define DWMCI_INTMSK_TXDR (1 << 4)
+#define DWMCI_INTMSK_RXDR (1 << 5)
+#define DWMCI_INTMSK_DCRC (1 << 7)
+#define DWMCI_INTMSK_RTO (1 << 8)
+#define DWMCI_INTMSK_DRTO (1 << 9)
+#define DWMCI_INTMSK_HTO (1 << 10)
+#define DWMCI_INTMSK_FRUN (1 << 11)
+#define DWMCI_INTMSK_HLE (1 << 12)
+#define DWMCI_INTMSK_SBE (1 << 13)
+#define DWMCI_INTMSK_ACD (1 << 14)
+#define DWMCI_INTMSK_EBE (1 << 15)
+
+/* Raw interrupt Regsiter */
+#define DWMCI_DATA_ERR (DWMCI_INTMSK_EBE | DWMCI_INTMSK_SBE | DWMCI_INTMSK_HLE |\
+ DWMCI_INTMSK_FRUN | DWMCI_INTMSK_EBE | DWMCI_INTMSK_DCRC)
+#define DWMCI_DATA_TOUT (DWMCI_INTMSK_HTO | DWMCI_INTMSK_DRTO)
+/* CTRL register */
+#define DWMCI_CTRL_RESET (1 << 0)
+#define DWMCI_CTRL_FIFO_RESET (1 << 1)
+#define DWMCI_CTRL_DMA_RESET (1 << 2)
+#define DWMCI_DMA_EN (1 << 5)
+#define DWMCI_CTRL_SEND_AS_CCSD (1 << 10)
+#define DWMCI_IDMAC_EN (1 << 25)
+#define DWMCI_RESET_ALL (DWMCI_CTRL_RESET | DWMCI_CTRL_FIFO_RESET |\
+ DWMCI_CTRL_DMA_RESET)
+
+/* CMD register */
+#define DWMCI_CMD_RESP_EXP (1 << 6)
+#define DWMCI_CMD_RESP_LENGTH (1 << 7)
+#define DWMCI_CMD_CHECK_CRC (1 << 8)
+#define DWMCI_CMD_DATA_EXP (1 << 9)
+#define DWMCI_CMD_RW (1 << 10)
+#define DWMCI_CMD_SEND_STOP (1 << 12)
+#define DWMCI_CMD_ABORT_STOP (1 << 14)
+#define DWMCI_CMD_PRV_DAT_WAIT (1 << 13)
+#define DWMCI_CMD_UPD_CLK (1 << 21)
+#define DWMCI_CMD_USE_HOLD_REG (1 << 29)
+#define DWMCI_CMD_START (1 << 31)
+
+/* CLKENA register */
+#define DWMCI_CLKEN_ENABLE (1 << 0)
+#define DWMCI_CLKEN_LOW_PWR (1 << 16)
+
+/* Card-type registe */
+#define DWMCI_CTYPE_1BIT 0
+#define DWMCI_CTYPE_4BIT (1 << 0)
+#define DWMCI_CTYPE_8BIT (1 << 16)
+
+/* Status Register */
+#define DWMCI_BUSY (1 << 9)
+
+#define DWMCI_IDMAC_OWN (1 << 31)
+#define DWMCI_IDMAC_CH (1 << 4)
+#define DWMCI_IDMAC_FS (1 << 3)
+#define DWMCI_IDMAC_LD (1 << 2)
+
+/* Bus Mode Register */
+#define DWMCI_BMOD_IDMAC_RESET (1 << 0)
+#define DWMCI_BMOD_IDMAC_FB (1 << 1)
+#define DWMCI_BMOD_IDMAC_EN (1 << 7)
+
+struct dwmci_host {
+ char *name;
+ void *ioaddr;
+ unsigned int quirks;
+ unsigned int caps;
+ unsigned int version;
+ unsigned int clock;
+ unsigned int bus_hz;
+ int dev_index;
+ int buswidth;
+ u32 fifoth_val;
+ struct mmc *mmc;
+
+ void (*clksel)(struct dwmci_host *host);
+ unsigned int (*mmc_clk)(int dev_index);
+};
+
+struct dwmci_idmac {
+ u32 des0;
+ u32 des1;
+ u32 des2;
+ u32 des3;
+};
+
+static inline void dwmci_writel(struct dwmci_host *host, int reg, u32 val)
+{
+ writel(val, host->ioaddr + reg);
+}
+
+static inline void dwmci_writew(struct dwmci_host *host, int reg, u16 val)
+{
+ writew(val, host->ioaddr + reg);
+}
+
+static inline void dwmci_writeb(struct dwmci_host *host, int reg, u8 val)
+{
+ writeb(val, host->ioaddr + reg);
+}
+static inline u32 dwmci_readl(struct dwmci_host *host, int reg)
+{
+ return readl(host->ioaddr + reg);
+}
+
+static inline u16 dwmci_readw(struct dwmci_host *host, int reg)
+{
+ return readw(host->ioaddr + reg);
+}
+
+static inline u8 dwmci_readb(struct dwmci_host *host, int reg)
+{
+ return readb(host->ioaddr + reg);
+}
+
+int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk, int index);
+#endif /* __DWMMC_HW_H */
3
4

[U-Boot] Configure a Numonyx Axcell M29EW on a MPC8323 board
by SETTE AGOSTINO - technolabs 15 Oct '12
by SETTE AGOSTINO - technolabs 15 Oct '12
15 Oct '12
Hi all,
I have a card with a MPC8323 and I would like to access a Numonyx Axcell M29EW FLASH.
After porting the U-Boot 2012.10-rc1 for MPC8323ERDB to my own hardware I have the following with "flinfo":
Bank # 1: CFI conformant flash (16 x 16) Size: 256 MB in 2048 Sectors
AMD Standard command set, Manufacturer ID: 0x89, Device ID: 0x227E4801
Erase timeout: 4096 ms, write timeout: 2 ms
Buffer write timeout: 5 ms, buffer size: 1024 bytes
If I digit:
MPC8323=> md 0xa3fffff0
a3fffff0: ffffffff ffffffff ffffffff ffffffff ................
a4000000:Machine check in kernel mode.
Caused by (from msr): regs 0ff7abf8 Unknown values in msr
NIP: 00001124 XER: 20000000 LR: 0FFDE5A0 REGS: 0ff7abf8 TRAP: 0200 DAR: 00000000
MSR: 00001000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
GPR00: 0FFDE5A0 0FF7ACE8 0FF7AF30 00000009 00000001 00000004 00000000 00000000
GPR08: 00000000 00000020 00000030 00000000 48024024 0B4EDE9E 00000000 00000000
GPR16: 0FFF79B4 00000000 0FFEBFBC 0FFF13E8 0FFE82A0 0FFF13F0 00000008 A4000000
GPR24: A4000000 0FF7ACF0 0000003C 00000000 00000004 00000004 0FFFC2B0 A4000000 Call backtrace:
0FFDE5A0 0FFC88E0 0FFCC2C8 0FFD1E0C 0FFD1564 0FFD16D4 0FFD3F70 0FFC2560 0FFC0608 machine check Resetting the board.
This may be related to the Local Bus Controller (LBC) at 26-bits, but the hardware has two signals (PD6 and PD7) to manage the upper addresses.
So, my question is:
How to modify u-boot for MPC8323 so the entire flash memory could be accessed? I mean, how to move the two signals above to address the entire memory?
Here is the u-boot/include/configs/MPC8323.h related to the flash
/*
* FLASH on the Local Bus
*/
#define CONFIG_SYS_FLASH_CFI /* use the Common Flash Interface */
#define CONFIG_FLASH_CFI_DRIVER /* use the CFI driver */
#define CONFIG_SYS_FLASH_BASE 0xA0000000 /* FLASH base address */
#define CONFIG_SYS_FLASH_SIZE 512
#define CONFIG_SYS_FLASH_PROTECTION 1 /* Use h/w Flash protection. */
#define CONFIG_SYS_LBLAWBAR0_PRELIM CONFIG_SYS_FLASH_BASE /* Window base at flash base */
#define CONFIG_SYS_LBLAWAR0_PRELIM 0x8000001C
#define CONFIG_SYS_BR0_PRELIM (CONFIG_SYS_FLASH_BASE | /* Flash Base address */ \
(2 << BR_PS_SHIFT) | /* 16 bit port size */ \
BR_V) /* valid */
@
#define CONFIG_SYS_OR0_PRELIM 0x00007ff7 /* 512MB Flash size */
#define CONFIG_SYS_MAX_FLASH_BANKS 1 /* number of banks */
#define CONFIG_SYS_MAX_FLASH_SECT 2053 /* sectors per device */
#undef CONFIG_SYS_FLASH_CHECKSUM
Thanks in advance for your support.
Best Regards,
Agostino Sette
2
4