LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [patch v10 1/4] USB: add Cypress c67x00 low level interface code
From: Peter Korsgaard @ 2008-02-21 15:34 UTC (permalink / raw)
  To: dbrownell, linux-usb, linuxppc-dev, grant.likely, stern, greg
In-Reply-To: <20080221153450.854136000@sunsite.dk>

This patch adds the low level support code for the Cypress c67x00 family of
OTG controllers.  The low level code is responsible for register access and
implements the software protocol for communicating with the 16bit
microcontroller inside the c67x00 device.

Communication is done over the HPI interface (16bit SRAM-like parallel bus).

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
---
 drivers/usb/c67x00/c67x00-ll-hpi.c |  405 +++++++++++++++++++++++++++++++++++++
 drivers/usb/c67x00/c67x00.h        |  285 ++++++++++++++++++++++++++
 2 files changed, 690 insertions(+)

Index: linux-2.6/drivers/usb/c67x00/c67x00.h
===================================================================
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/c67x00.h
@@ -0,0 +1,285 @@
+/*
+ * c67x00.h: Cypress C67X00 USB register and field definitions
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple host controller drivers inside the linux kernel.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#ifndef _USB_C67X00_H
+#define _USB_C67X00_H
+
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+/* ---------------------------------------------------------------------
+ * Cypress C67x00 register definitions
+ */
+
+/* Hardware Revision Register */
+#define HW_REV_REG		0xC004
+
+/* General USB registers */
+/* ===================== */
+
+/* USB Control Register */
+#define USB_CTL_REG(x)		((x) ? 0xC0AA : 0xC08A)
+
+#define LOW_SPEED_PORT(x)	((x) ? 0x0800 : 0x0400)
+#define HOST_MODE		0x0200
+#define PORT_RES_EN(x)		((x) ? 0x0100 : 0x0080)
+#define SOF_EOP_EN(x)		((x) ? 0x0002 : 0x0001)
+
+/* USB status register - Notice it has different content in hcd/udc mode */
+#define USB_STAT_REG(x)		((x) ? 0xC0B0 : 0xC090)
+
+#define EP0_IRQ_FLG		0x0001
+#define EP1_IRQ_FLG		0x0002
+#define EP2_IRQ_FLG		0x0004
+#define EP3_IRQ_FLG		0x0008
+#define EP4_IRQ_FLG		0x0010
+#define EP5_IRQ_FLG		0x0020
+#define EP6_IRQ_FLG		0x0040
+#define EP7_IRQ_FLG		0x0080
+#define RESET_IRQ_FLG		0x0100
+#define SOF_EOP_IRQ_FLG		0x0200
+#define ID_IRQ_FLG		0x4000
+#define VBUS_IRQ_FLG		0x8000
+
+/* USB Host only registers */
+/* ======================= */
+
+/* Host n Control Register */
+#define HOST_CTL_REG(x)		((x) ? 0xC0A0 : 0xC080)
+
+#define PREAMBLE_EN		0x0080	/* Preamble enable */
+#define SEQ_SEL			0x0040	/* Data Toggle Sequence Bit Select */
+#define ISO_EN			0x0010	/* Isochronous enable  */
+#define ARM_EN			0x0001	/* Arm operation */
+
+/* Host n Interrupt Enable Register */
+#define HOST_IRQ_EN_REG(x)	((x) ? 0xC0AC : 0xC08C)
+
+#define SOF_EOP_IRQ_EN		0x0200	/* SOF/EOP Interrupt Enable  */
+#define SOF_EOP_TMOUT_IRQ_EN	0x0800	/* SOF/EOP Timeout Interrupt Enable  */
+#define ID_IRQ_EN		0x4000	/* ID interrupt enable */
+#define VBUS_IRQ_EN		0x8000	/* VBUS interrupt enable */
+#define DONE_IRQ_EN		0x0001	/* Done Interrupt Enable  */
+
+/* USB status register */
+#define HOST_STAT_MASK		0x02FD
+#define PORT_CONNECT_CHANGE(x)	((x) ? 0x0020 : 0x0010)
+#define PORT_SE0_STATUS(x)	((x) ? 0x0008 : 0x0004)
+
+/* Host Frame Register */
+#define HOST_FRAME_REG(x)	((x) ? 0xC0B6 : 0xC096)
+
+#define HOST_FRAME_MASK		0x07FF
+
+/* USB Peripheral only registers */
+/* ============================= */
+
+/* Device n Port Sel reg */
+#define DEVICE_N_PORT_SEL(x)	((x) ? 0xC0A4 : 0xC084)
+
+/* Device n Interrupt Enable Register */
+#define DEVICE_N_IRQ_EN_REG(x)	((x) ? 0xC0AC : 0xC08C)
+
+#define DEVICE_N_ENDPOINT_N_CTL_REG(dev, ep)	((dev)  		\
+						 ? (0x0280 + (ep << 4)) \
+						 : (0x0200 + (ep << 4)))
+#define DEVICE_N_ENDPOINT_N_STAT_REG(dev, ep)	((dev)			\
+						 ? (0x0286 + (ep << 4)) \
+						 : (0x0206 + (ep << 4)))
+
+#define DEVICE_N_ADDRESS(dev)	((dev) ? (0xC0AE) : (0xC08E))
+
+/* HPI registers */
+/* ============= */
+
+/* HPI Status register */
+#define SOFEOP_FLG(x)		(1 << ((x) ? 12 : 10))
+#define SIEMSG_FLG(x)		(1 << (4 + (x)))
+#define RESET_FLG(x)		((x) ? 0x0200 : 0x0002)
+#define DONE_FLG(x)		(1 << (2 + (x)))
+#define RESUME_FLG(x)		(1 << (6 + (x)))
+#define MBX_OUT_FLG		0x0001	/* Message out available */
+#define MBX_IN_FLG		0x0100
+#define ID_FLG			0x4000
+#define VBUS_FLG		0x8000
+
+/* Interrupt routing register */
+#define HPI_IRQ_ROUTING_REG	0x0142
+
+#define HPI_SWAP_ENABLE(x)	((x) ? 0x0100 : 0x0001)
+#define RESET_TO_HPI_ENABLE(x)	((x) ? 0x0200 : 0x0002)
+#define DONE_TO_HPI_ENABLE(x)	((x) ? 0x0008 : 0x0004)
+#define RESUME_TO_HPI_ENABLE(x)	((x) ? 0x0080 : 0x0040)
+#define SOFEOP_TO_HPI_EN(x)	((x) ? 0x2000 : 0x0800)
+#define SOFEOP_TO_CPU_EN(x)	((x) ? 0x1000 : 0x0400)
+#define ID_TO_HPI_ENABLE	0x4000
+#define VBUS_TO_HPI_ENABLE	0x8000
+
+/* SIE msg registers */
+#define SIEMSG_REG(x)		((x) ? 0x0148 : 0x0144)
+
+#define HUSB_TDListDone		0x1000
+
+#define SUSB_EP0_MSG		0x0001
+#define SUSB_EP1_MSG		0x0002
+#define SUSB_EP2_MSG		0x0004
+#define SUSB_EP3_MSG		0x0008
+#define SUSB_EP4_MSG		0x0010
+#define SUSB_EP5_MSG		0x0020
+#define SUSB_EP6_MSG		0x0040
+#define SUSB_EP7_MSG		0x0080
+#define SUSB_RST_MSG		0x0100
+#define SUSB_SOF_MSG		0x0200
+#define SUSB_CFG_MSG		0x0400
+#define SUSB_SUS_MSG		0x0800
+#define SUSB_ID_MSG	       	0x4000
+#define SUSB_VBUS_MSG		0x8000
+
+/* BIOS interrupt routines */
+
+#define SUSBx_RECEIVE_INT(x)	((x) ? 97 : 81)
+#define SUSBx_SEND_INT(x)	((x) ? 96 : 80)
+
+#define SUSBx_DEV_DESC_VEC(x)	((x) ? 0x00D4 : 0x00B4)
+#define SUSBx_CONF_DESC_VEC(x)	((x) ? 0x00D6 : 0x00B6)
+#define SUSBx_STRING_DESC_VEC(x) ((x) ? 0x00D8 : 0x00B8)
+
+#define CY_HCD_BUF_ADDR		0x500	/* Base address for host */
+#define SIE_TD_SIZE		0x200	/* size of the td list */
+#define SIE_TD_BUF_SIZE		0x400	/* size of the data buffer */
+
+#define SIE_TD_OFFSET(host)	((host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0)
+#define SIE_BUF_OFFSET(host)	(SIE_TD_OFFSET(host) + SIE_TD_SIZE)
+
+/* Base address of HCD + 2 x TD_SIZE + 2 x TD_BUF_SIZE */
+#define CY_UDC_REQ_HEADER_BASE	0x1100
+/* 8- byte request headers for IN/OUT transfers */
+#define CY_UDC_REQ_HEADER_SIZE	8
+
+#define CY_UDC_REQ_HEADER_ADDR(ep_num)	(CY_UDC_REQ_HEADER_BASE + \
+					 ((ep_num) * CY_UDC_REQ_HEADER_SIZE))
+#define CY_UDC_DESC_BASE_ADDRESS	(CY_UDC_REQ_HEADER_ADDR(8))
+
+#define CY_UDC_BIOS_REPLACE_BASE	0x1800
+#define CY_UDC_REQ_BUFFER_BASE		0x2000
+#define CY_UDC_REQ_BUFFER_SIZE		0x0400
+#define CY_UDC_REQ_BUFFER_ADDR(ep_num)	(CY_UDC_REQ_BUFFER_BASE + \
+					 ((ep_num) * CY_UDC_REQ_BUFFER_SIZE))
+
+/* ---------------------------------------------------------------------
+ * Driver data structures
+ */
+
+struct c67x00_device;
+
+/**
+ * struct c67x00_sie - Common data associated with a SIE
+ * @lock: lock to protect this struct and the associated chip registers
+ * @private_data: subdriver dependent data
+ * @irq: subdriver dependent irq handler, set NULL when not used
+ * @dev: link to common driver structure
+ * @sie_num: SIE number on chip, starting from 0
+ * @mode: SIE mode (host/peripheral/otg/not used)
+ */
+struct c67x00_sie {
+	/* Entries to be used by the subdrivers */
+	spinlock_t lock;	/* protect this structure */
+	void *private_data;
+	void (*irq) (struct c67x00_sie *sie, u16 int_status, u16 msg);
+
+	/* Read only: */
+	struct c67x00_device *dev;
+	int sie_num;
+	int mode;
+};
+
+#define sie_dev(s)	(&(s)->dev->pdev->dev)
+
+/**
+ * struct c67x00_lcp
+ */
+struct c67x00_lcp {
+	/* Internal use only */
+	struct mutex mutex;
+	struct completion msg_received;
+	u16 last_msg;
+};
+
+/*
+ * struct c67x00_hpi
+ */
+struct c67x00_hpi {
+	void __iomem *base;
+	int regstep;
+	spinlock_t lock;
+	struct c67x00_lcp lcp;
+};
+
+#define C67X00_SIES	2
+#define C67X00_PORTS	2
+
+/**
+ * struct c67x00_device - Common data associated with a c67x00 instance
+ * @hpi: hpi addresses
+ * @sie: array of sie's on this chip
+ * @pdev: platform device of instance
+ * @pdata: configuration provided by the platform
+ */
+struct c67x00_device {
+	struct c67x00_hpi hpi;
+	struct c67x00_sie sie[C67X00_SIES];
+	struct platform_device *pdev;
+	struct c67x00_platform_data *pdata;
+};
+
+/* ---------------------------------------------------------------------
+ * Low level interface functions
+ */
+
+/* Host Port Interface (HPI) functions */
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev);
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev);
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie);
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie);
+
+/* General functions */
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num);
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie);
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits);
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie);
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+			      void *data, int len);
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+			     void *data, int len);
+
+/* Called by c67x00_irq to handle lcp interrupts */
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status);
+
+/* Setup and teardown */
+void c67x00_ll_init(struct c67x00_device *dev);
+void c67x00_ll_release(struct c67x00_device *dev);
+int c67x00_ll_reset(struct c67x00_device *dev);
+
+#endif				/* _USB_C67X00_H */
Index: linux-2.6/drivers/usb/c67x00/c67x00-ll-hpi.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/c67x00-ll-hpi.c
@@ -0,0 +1,405 @@
+/*
+ * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple host controller drivers inside the linux kernel.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <linux/usb/c67x00.h>
+#include "c67x00.h"
+
+#define COMM_REGS 14
+
+struct c67x00_lcp_int_data {
+	u16 regs[COMM_REGS];
+};
+
+/* -------------------------------------------------------------------------- */
+/* Interface definitions */
+
+#define COMM_ACK			0x0FED
+#define COMM_NAK			0xDEAD
+
+#define COMM_RESET			0xFA50
+#define COMM_EXEC_INT			0xCE01
+#define COMM_INT_NUM			0x01C2
+
+/* Registers 0 to COMM_REGS-1 */
+#define COMM_R(x)			(0x01C4 + 2 * (x))
+
+#define HUSB_SIE_pCurrentTDPtr(x)	((x) ? 0x01B2 : 0x01B0)
+#define HUSB_SIE_pTDListDone_Sem(x)	((x) ? 0x01B8 : 0x01B6)
+#define HUSB_pEOT			0x01B4
+
+/* Software interrupts */
+/* 114, 115: */
+#define HUSB_SIE_INIT_INT(x)		((x) ? 0x0073 : 0x0072)
+#define HUSB_RESET_INT			0x0074
+
+#define SUSB_INIT_INT			0x0071
+#define SUSB_INIT_INT_LOC		(SUSB_INIT_INT * 2)
+
+/* -----------------------------------------------------------------------
+ * HPI implementation
+ *
+ * The c67x00 chip also support control via SPI or HSS serial
+ * interfaces.  However, this driver assumes that register access can
+ * be performed from IRQ context.  While this is a safe assuption with
+ * the HPI interface, it is not true for the serial interfaces.
+ */
+
+/* HPI registers */
+#define HPI_DATA	0
+#define HPI_MAILBOX	1
+#define HPI_ADDR	2
+#define HPI_STATUS	3
+
+static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)
+{
+	return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)
+{
+	__raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg)
+{
+	hpi_write_reg(dev, HPI_ADDR, reg);
+	return hpi_read_reg(dev, HPI_DATA);
+}
+
+static u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
+{
+	u16 value;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->hpi.lock, flags);
+	value = hpi_read_word_nolock(dev, reg);
+	spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+	return value;
+}
+
+static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value)
+{
+	hpi_write_reg(dev, HPI_ADDR, reg);
+	hpi_write_reg(dev, HPI_DATA, value);
+}
+
+static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->hpi.lock, flags);
+	hpi_write_word_nolock(dev, reg, value);
+	spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
+				 u16 *data, u16 count)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&dev->hpi.lock, flags);
+
+	hpi_write_reg(dev, HPI_ADDR, addr);
+	for (i = 0; i < count; i++)
+		hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++));
+
+	spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
+				u16 *data, u16 count)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&dev->hpi.lock, flags);
+	hpi_write_reg(dev, HPI_ADDR, addr);
+	for (i = 0; i < count; i++)
+		*data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA));
+
+	spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+	u16 value;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->hpi.lock, flags);
+	value = hpi_read_word_nolock(dev, reg);
+	hpi_write_word_nolock(dev, reg, value | mask);
+	spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+	u16 value;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->hpi.lock, flags);
+	value = hpi_read_word_nolock(dev, reg);
+	hpi_write_word_nolock(dev, reg, value & ~mask);
+	spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static u16 hpi_recv_mbox(struct c67x00_device *dev)
+{
+	u16 value;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->hpi.lock, flags);
+	value = hpi_read_reg(dev, HPI_MAILBOX);
+	spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+	return value;
+}
+
+static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->hpi.lock, flags);
+	hpi_write_reg(dev, HPI_MAILBOX, value);
+	spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+	return value;
+}
+
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev)
+{
+	u16 value;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->hpi.lock, flags);
+	value = hpi_read_reg(dev, HPI_STATUS);
+	spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+	return value;
+}
+
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
+{
+	int i;
+
+	hpi_recv_mbox(dev);
+	c67x00_ll_hpi_status(dev);
+	hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
+
+	for (i = 0; i < C67X00_SIES; i++) {
+		hpi_write_word(dev, SIEMSG_REG(i), 0);
+		hpi_read_word(dev, SIEMSG_REG(i));
+	}
+}
+
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie)
+{
+	hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+		     SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
+{
+	hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+		       SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+/* Transactions */
+
+static inline u16 ll_recv_msg(struct c67x00_device *dev)
+{
+	u16 res;
+
+	res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
+	WARN_ON(!res);
+
+	return (res == 0) ? -EIO : 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* General functions */
+
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num)
+{
+	u16 val;
+
+	val = hpi_read_word(dev, SIEMSG_REG(sie_num));
+	/* clear register to allow next message */
+	hpi_write_word(dev, SIEMSG_REG(sie_num), 0);
+
+	return val;
+}
+
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
+{
+	return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
+}
+
+/**
+ * c67x00_ll_usb_clear_status - clear the USB status bits
+ */
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
+{
+	hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
+}
+
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
+{
+	return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
+				struct c67x00_lcp_int_data *data)
+{
+	int i, rc;
+
+	mutex_lock(&dev->hpi.lcp.mutex);
+	hpi_write_word(dev, COMM_INT_NUM, nr);
+	for (i = 0; i < COMM_REGS; i++)
+		hpi_write_word(dev, COMM_R(i), data->regs[i]);
+	hpi_send_mbox(dev, COMM_EXEC_INT);
+	rc = ll_recv_msg(dev);
+	mutex_unlock(&dev->hpi.lcp.mutex);
+
+	return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
+{
+	if ((int_status & MBX_OUT_FLG) == 0)
+		return;
+
+	dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
+	complete(&dev->hpi.lcp.msg_received);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int c67x00_ll_reset(struct c67x00_device *dev)
+{
+	int rc;
+
+	mutex_lock(&dev->hpi.lcp.mutex);
+	hpi_send_mbox(dev, COMM_RESET);
+	rc = ll_recv_msg(dev);
+	mutex_unlock(&dev->hpi.lcp.mutex);
+
+	return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_ll_write_mem_le16 - write into c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+			      void *data, int len)
+{
+	u8 *buf = data;
+
+	/* Sanity check */
+	if (addr + len > 0xffff) {
+		dev_err(&dev->pdev->dev,
+			"Trying to write beyond writable region!\n");
+		return;
+	}
+
+	if (addr & 0x01) {
+		/* unaligned access */
+		u16 tmp;
+		tmp = hpi_read_word(dev, addr - 1);
+		tmp = (tmp & 0x00ff) | (*buf++ << 8);
+		hpi_write_word(dev, addr - 1, tmp);
+		addr++;
+		len--;
+	}
+
+	hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2);
+	buf += len & ~0x01;
+	addr += len & ~0x01;
+	len &= 0x01;
+
+	if (len) {
+		u16 tmp;
+		tmp = hpi_read_word(dev, addr);
+		tmp = (tmp & 0xff00) | *buf;
+		hpi_write_word(dev, addr, tmp);
+	}
+}
+
+/**
+ * c67x00_ll_read_mem_le16 - read from c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+			     void *data, int len)
+{
+	u8 *buf = data;
+
+	if (addr & 0x01) {
+		/* unaligned access */
+		u16 tmp;
+		tmp = hpi_read_word(dev, addr - 1);
+		*buf++ = (tmp >> 8) & 0x00ff;
+		addr++;
+		len--;
+	}
+
+	hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2);
+	buf += len & ~0x01;
+	addr += len & ~0x01;
+	len &= 0x01;
+
+	if (len) {
+		u16 tmp;
+		tmp = hpi_read_word(dev, addr);
+		*buf = tmp & 0x00ff;
+	}
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_init(struct c67x00_device *dev)
+{
+	mutex_init(&dev->hpi.lcp.mutex);
+	init_completion(&dev->hpi.lcp.msg_received);
+}
+
+void c67x00_ll_release(struct c67x00_device *dev)
+{
+}

--
Bye, Peter Korsgaard

^ permalink raw reply

* [patch v10 2/4] USB: add Cypress c67x00 OTG controller core driver
From: Peter Korsgaard @ 2008-02-21 15:34 UTC (permalink / raw)
  To: dbrownell, linux-usb, linuxppc-dev, grant.likely, stern, greg
In-Reply-To: <20080221153450.854136000@sunsite.dk>

This patch add the core driver for the c67x00 USB OTG controller.  The core
driver is responsible for the platform bus binding and creating either
USB HCD or USB Gadget instances for each of the serial interface engines
on the chip.

This driver does not directly implement the HCD or gadget behaviours; it
just controls access to the chip.

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
---
 MAINTAINERS                     |    6 +
 drivers/usb/c67x00/c67x00-drv.c |  229 ++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/c67x00.h      |   48 ++++++++
 3 files changed, 283 insertions(+)

Index: linux-2.6/drivers/usb/c67x00/c67x00-drv.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/c67x00-drv.c
@@ -0,0 +1,229 @@
+/*
+ * c67x00-drv.c: Cypress C67X00 USB Common infrastructure
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple host controller drivers inside the linux kernel.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+/*
+ * This file implements the common infrastructure for using the c67x00.
+ * It is both the link between the platform configuration and subdrivers and
+ * the link between the common hardware parts and the subdrivers (e.g.
+ * interrupt handling).
+ *
+ * The c67x00 has 2 SIE's (serial interface engine) wich can be configured
+ * to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG).
+ *
+ * Depending on the platform configuration, the SIE's are created and
+ * the corresponding subdriver is initialized (c67x00_probe_sie).
+ */
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/usb/c67x00.h>
+#include <asm/io.h>
+
+#include "c67x00.h"
+
+static void c67x00_probe_sie(struct c67x00_sie *sie,
+			     struct c67x00_device *dev, int sie_num)
+{
+	spin_lock_init(&sie->lock);
+	sie->dev = dev;
+	sie->sie_num = sie_num;
+	sie->mode = c67x00_sie_config(dev->pdata->sie_config, sie_num);
+
+	switch (sie->mode) {
+	case C67X00_SIE_UNUSED:
+		dev_info(sie_dev(sie),
+			 "Not using SIE %d as requested\n", sie->sie_num);
+		break;
+
+	default:
+		dev_err(sie_dev(sie),
+			"Unsupported configuration: 0x%x for SIE %d\n",
+			sie->mode, sie->sie_num);
+		break;
+	}
+}
+
+static void c67x00_remove_sie(struct c67x00_sie *sie)
+{
+}
+
+static irqreturn_t c67x00_irq(int irq, void *__dev)
+{
+	struct c67x00_device *c67x00 = __dev;
+	struct c67x00_sie *sie;
+	u16 msg, int_status;
+	int i, count = 8;
+
+	int_status = c67x00_ll_hpi_status(c67x00);
+	if (!int_status)
+		return IRQ_NONE;
+
+	while (int_status != 0 && (count-- >= 0)) {
+		c67x00_ll_irq(c67x00, int_status);
+		for (i = 0; i < C67X00_SIES; i++) {
+			sie = &c67x00->sie[i];
+			msg = 0;
+			if (int_status & SIEMSG_FLG(i))
+				msg = c67x00_ll_fetch_siemsg(c67x00, i);
+			if (sie->irq)
+				sie->irq(sie, int_status, msg);
+		}
+		int_status = c67x00_ll_hpi_status(c67x00);
+	}
+
+	if (int_status)
+		dev_warn(&c67x00->pdev->dev, "Not all interrupts handled! "
+			 "status = 0x%04x\n", int_status);
+
+	return IRQ_HANDLED;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __devinit c67x00_drv_probe(struct platform_device *pdev)
+{
+	struct c67x00_device *c67x00;
+	struct c67x00_platform_data *pdata;
+	struct resource *res, *res2;
+	int ret, i;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res2)
+		return -ENODEV;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata)
+		return -ENODEV;
+
+	c67x00 = kzalloc(sizeof(*c67x00), GFP_KERNEL);
+	if (!c67x00)
+		return -ENOMEM;
+
+	if (!request_mem_region(res->start, res->end - res->start + 1,
+				pdev->name)) {
+		dev_err(&pdev->dev, "Memory region busy\n");
+		ret = -EBUSY;
+		goto request_mem_failed;
+	}
+	c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1);
+	if (!c67x00->hpi.base) {
+		dev_err(&pdev->dev, "Unable to map HPI registers\n");
+		ret = -EIO;
+		goto map_failed;
+	}
+
+	spin_lock_init(&c67x00->hpi.lock);
+	c67x00->hpi.regstep = pdata->hpi_regstep;
+	c67x00->pdata = pdev->dev.platform_data;
+	c67x00->pdev = pdev;
+
+	c67x00_ll_init(c67x00);
+	c67x00_ll_hpi_reg_init(c67x00);
+
+	ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot claim IRQ\n");
+		goto request_irq_failed;
+	}
+
+	ret = c67x00_ll_reset(c67x00);
+	if (ret) {
+		dev_err(&pdev->dev, "Device reset failed\n");
+		goto reset_failed;
+	}
+
+	for (i = 0; i < C67X00_SIES; i++)
+		c67x00_probe_sie(&c67x00->sie[i], c67x00, i);
+
+	platform_set_drvdata(pdev, c67x00);
+
+	return 0;
+
+ reset_failed:
+	free_irq(res2->start, c67x00);
+ request_irq_failed:
+	iounmap(c67x00->hpi.base);
+ map_failed:
+	release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+	kfree(c67x00);
+
+	return ret;
+}
+
+static int __devexit c67x00_drv_remove(struct platform_device *pdev)
+{
+	struct c67x00_device *c67x00 = platform_get_drvdata(pdev);
+	struct resource *res;
+	int i;
+
+	for (i = 0; i < C67X00_SIES; i++)
+		c67x00_remove_sie(&c67x00->sie[i]);
+
+	c67x00_ll_release(c67x00);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res)
+		free_irq(res->start, c67x00);
+
+	iounmap(c67x00->hpi.base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res)
+		release_mem_region(res->start, res->end - res->start + 1);
+
+	kfree(c67x00);
+
+	return 0;
+}
+
+static struct platform_driver c67x00_driver = {
+	.probe	= c67x00_drv_probe,
+	.remove	= __devexit_p(c67x00_drv_remove),
+	.driver	= {
+		.owner = THIS_MODULE,
+		.name = "c67x00",
+	},
+};
+
+static int __init c67x00_init(void)
+{
+	return platform_driver_register(&c67x00_driver);
+}
+
+static void __exit c67x00_exit(void)
+{
+	platform_driver_unregister(&c67x00_driver);
+}
+
+module_init(c67x00_init);
+module_exit(c67x00_exit);
+
+MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
+MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");
+MODULE_LICENSE("GPL");
Index: linux-2.6/include/linux/usb/c67x00.h
===================================================================
--- /dev/null
+++ linux-2.6/include/linux/usb/c67x00.h
@@ -0,0 +1,48 @@
+/*
+ * usb_c67x00.h: platform definitions for the Cypress C67X00 USB chip
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#ifndef _LINUX_USB_C67X00_H
+#define _LINUX_USB_C67X00_H
+
+/* SIE configuration */
+#define C67X00_SIE_UNUSED	0
+#define C67X00_SIE_HOST		1
+#define C67X00_SIE_PERIPHERAL_A	2	/* peripheral on A port */
+#define C67X00_SIE_PERIPHERAL_B	3	/* peripheral on B port */
+
+#define c67x00_sie_config(config, n)  (((config)>>(4*(n)))&0x3)
+
+#define C67X00_SIE1_UNUSED	        (C67X00_SIE_UNUSED		<< 0)
+#define C67X00_SIE1_HOST	        (C67X00_SIE_HOST		<< 0)
+#define C67X00_SIE1_PERIPHERAL_A	(C67X00_SIE_PERIPHERAL_A	<< 0)
+#define C67X00_SIE1_PERIPHERAL_B	(C67X00_SIE_PERIPHERAL_B	<< 0)
+
+#define C67X00_SIE2_UNUSED		(C67X00_SIE_UNUSED		<< 4)
+#define C67X00_SIE2_HOST		(C67X00_SIE_HOST		<< 4)
+#define C67X00_SIE2_PERIPHERAL_A	(C67X00_SIE_PERIPHERAL_A	<< 4)
+#define C67X00_SIE2_PERIPHERAL_B	(C67X00_SIE_PERIPHERAL_B	<< 4)
+
+struct c67x00_platform_data {
+	int sie_config;			/* SIEs config (C67X00_SIEx_*) */
+	unsigned long hpi_regstep;	/* Step between HPI registers  */
+};
+
+#endif /* _LINUX_USB_C67X00_H */
Index: linux-2.6/MAINTAINERS
===================================================================
--- linux-2.6.orig/MAINTAINERS
+++ linux-2.6/MAINTAINERS
@@ -3949,6 +3949,12 @@
 S:	Maintained
 W:	http://www.kroah.com/linux-usb/
 
+USB CYPRESS C67X00 DRIVER
+P:	Peter Korsgaard
+M:	jacmet@sunsite.dk
+L:	linux-usb@vger.kernel.org
+S:	Maintained
+
 USB DAVICOM DM9601 DRIVER
 P:	Peter Korsgaard
 M:	jacmet@sunsite.dk

--
Bye, Peter Korsgaard

^ permalink raw reply

* [patch v10 4/4] USB: add Cypress c67x00 OTG controller gadget driver
From: Peter Korsgaard @ 2008-02-21 15:34 UTC (permalink / raw)
  To: dbrownell, linux-usb, linuxppc-dev, grant.likely, stern, greg
In-Reply-To: <20080221153450.854136000@sunsite.dk>

This patch adds USB gadget support for the Cypress c67x00 family of devices.

This is work in progress and not ready to be committed yet. I'm posting this
to show how it fits with the rest of the driver and to collect feedback.

The driver works good enought to use g_serial, but there are still issues
to be solved. The biggest issue is that endpoint 0 is currently handled by
the BIOS inside the c67x00, so the gadget stack never sees the data.
The BIOS also has other deficiencies, E.G. see the patching done in
c67x00_ll_susb_init().
---
 drivers/usb/Kconfig                |    2 
 drivers/usb/Makefile               |    2 
 drivers/usb/c67x00/Kconfig         |   21 
 drivers/usb/c67x00/Makefile        |    7 
 drivers/usb/c67x00/c67x00-drv.c    |   11 
 drivers/usb/c67x00/c67x00-hcd.h    |   13 
 drivers/usb/c67x00/c67x00-ll-hpi.c |  206 ++++++++
 drivers/usb/c67x00/c67x00-udc.c    |  905 +++++++++++++++++++++++++++++++++++++
 drivers/usb/c67x00/c67x00-udc.h    |   48 +
 drivers/usb/c67x00/c67x00.h        |   21 
 drivers/usb/gadget/Kconfig         |    7 
 drivers/usb/gadget/gadget_chips.h  |    8 
 drivers/usb/host/Kconfig           |   13 
 13 files changed, 1248 insertions(+), 16 deletions(-)

Index: linux-2.6/drivers/usb/c67x00/c67x00-udc.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/c67x00-udc.c
@@ -0,0 +1,905 @@
+/*
+ * c67x00-udc.c: Cypress C67X00 USB device controller
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple device controller drivers inside the linux kernel.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#include <linux/device.h>
+#include <linux/usb.h>
+#include <linux/usb/c67x00.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/ch9.h>
+
+#include "c67x00.h"
+#include "c67x00-udc.h"
+
+/* Defined in DEVICE n ENDPOINT STATUS REGISTERS */
+#define OVERFLOW_FLG		0x0800	/* Receive overflow */
+#define UNDERFLOW_FLG		0x0400	/* Receive underflow */
+#define OUT_EXCEPTION_FLG	0x0200	/* OUT received when armed for IN */
+#define IN_EXCEPTION_FLG	0x0100	/* IN received when armed for OUT */
+#define STALL_FLG		0x0080	/* Stall sent */
+#define NAK_FLG			0x0040	/* NAK sent */
+#define LENGTH_EXCEPT_FLG	0x0020	/* Overflow or Underflow occured */
+#define SETUP_FLG		0x0010	/* SETUP packet received */
+#define SEQ_STAT		0x0008	/* Last Data Toggle Sequence bit sent
+						or received */
+#define TIMEOUT_FLG		0x0004	/* Last transmission timed out */
+#define ERROR_FLG		0x0002	/* CRC Err detected in last
+						reception*/
+#define ACK_FLG			0x0001	/* Last transaction ACK'D (sent
+						or received) */
+
+/* Defined in DEVICE n ENDPOINT CONTROL REGISTERS */
+#define DIR_SEL_IN	0x0004	/* Last transmission timed out */
+#define EP_ENABLE	0x0002	/* Enable Endpoint */
+
+
+
+struct c67x00_request {
+	struct usb_request req;
+	struct list_head queue;
+};
+
+
+
+struct c67x00_udc_ep {
+	struct usb_ep ep;
+	struct c67x00_udc *udc;
+
+	struct list_head queue;
+	int ep_num;
+	int is_ep_in;
+	int enable;
+	int stopped;
+	int start_io;
+};
+
+#define C67X00_MAX_NB_END_POINTS 8
+
+struct c67x00_udc {
+	spinlock_t lock;
+	struct c67x00_sie *sie;
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+	struct c67x00_udc_ep ep[C67X00_MAX_NB_END_POINTS];
+	struct work_struct io_work;
+	int config_nr;
+	/* The highest string descriptor entry
+	   (used to retrieve descriptors from gadget driver) */
+	int top_str_id;
+	u16 string_desc_addr;
+};
+
+const static unsigned char get_descriptor_device[] = {
+	USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+	USB_REQ_GET_DESCRIPTOR,
+	0x00,
+	USB_DT_DEVICE,
+	0x00,
+	0x00,
+	0x12,
+	0x00
+};
+
+const static unsigned char get_descriptor_config[] = {
+	USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+	USB_REQ_GET_DESCRIPTOR,
+	0x00,
+	USB_DT_CONFIG,
+	0x00,
+	0x00,
+	0x40,
+	0x00
+};
+
+static unsigned char get_descriptor_string[] = {
+	USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+	USB_REQ_GET_DESCRIPTOR,
+	0x00,
+	USB_DT_STRING,
+	0x00,
+	0x00,
+	0xFF,
+	0x00
+};
+
+#define SIEx_DEV_DESC_LOC(x)	((x) ? (CY_UDC_DESC_BASE_ADDRESS + 0x200) \
+				 : CY_UDC_DESC_BASE_ADDRESS)
+#define SIEx_CONF_DESC_LOC(x)	(SIEx_DEV_DESC_LOC(x) + 32)
+
+/* ------------------------------------------------------------------------- */
+/* gadget ops */
+
+static int c67x00_get_frame(struct usb_gadget *_gadget)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_get_frame\n");
+	return -ENODEV;
+}
+
+static int c67x00_wakeup(struct usb_gadget *_gadget)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_wakeup\n");
+	return -ENODEV;
+}
+
+static int c67x00_selfpowered(struct usb_gadget *_gadget,
+			      int is_selfpowered)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_selfpowered\n");
+	return -ENODEV;
+}
+
+static int c67x00_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_vbus_session\n");
+	return -ENODEV;
+}
+
+static int c67x00_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_pullup\n");
+	return -ENODEV;
+}
+
+
+static const struct usb_gadget_ops c67x00_udc_ops = {
+	.get_frame = c67x00_get_frame,
+	.wakeup = c67x00_wakeup,
+	.set_selfpowered = c67x00_selfpowered,
+	.vbus_session = c67x00_vbus_session,
+	.pullup = c67x00_pullup
+};
+
+
+
+/*
+ * the sie and gadget_driver get probed/registered from 2 totally independant
+ * places, this datastructure binds them together
+ */
+static struct c67x00_udc controller = {
+	.gadget = {
+		.ops = &c67x00_udc_ops,
+		.name = "c67x00_udc",
+		.speed = USB_SPEED_FULL,
+		.is_dualspeed = 1,
+		.is_a_peripheral = 1,
+		.dev = {
+			.bus_id = "gadget",
+		},
+	},
+};
+
+
+/*----------------------------------------------------------------------------*/
+
+static void c67x00_udc_set_configuration(struct c67x00_sie *sie, u16 config)
+{
+	struct usb_ctrlrequest request;
+	struct c67x00_udc *udc = sie->private_data;
+
+	dev_dbg(sie_dev(sie), "set configuration %d\n", config);
+
+	request.bRequest = USB_REQ_SET_CONFIGURATION;
+	request.bRequestType = 0;
+	request.wValue = cpu_to_le16(config);
+	udc->driver->setup(&udc->gadget, &request);
+}
+
+static int c67x00_udc_parse_descriptor(struct c67x00_udc *udc,
+				       struct c67x00_request *req)
+{
+	int retval = 0;
+	u8 *buf = req->req.buf;
+
+	if (req->req.length < 2)
+		return 0;
+
+	switch (buf[1]) {
+	case USB_DT_DEVICE: {
+		struct usb_device_descriptor *desc = req->req.buf;
+
+		/* Look for the highest stringIndex */
+		if (desc->iManufacturer > udc->top_str_id)
+			udc->top_str_id = desc->iManufacturer;
+		if (desc->iProduct > udc->top_str_id)
+			udc->top_str_id = desc->iProduct;
+		if (desc->iSerialNumber > udc->top_str_id)
+			udc->top_str_id = desc->iSerialNumber;
+
+		/* Write descriptor to C67x00 memory */
+		c67x00_ll_write_mem_le16(udc->sie->dev,
+					 SIEx_DEV_DESC_LOC(udc->sie->sie_num),
+					 req->req.buf, req->req.length);
+
+		/* Write vector address to c67x00 */
+		c67x00_ll_set_device_descriptor_location(
+			udc->sie, SIEx_DEV_DESC_LOC(udc->sie->sie_num));
+
+		retval = 1;
+		break;
+	}
+
+	case USB_DT_CONFIG: {
+		struct usb_config_descriptor *desc = req->req.buf;
+		int offset;
+		u16 length;
+
+		/* store config number to pass to the gadget driver,
+		   once the c67x00 is configured */
+		udc->config_nr = desc->bConfigurationValue;
+
+		length = le16_to_cpu(desc->wTotalLength);
+
+		if (desc->iConfiguration > udc->top_str_id)
+			udc->top_str_id = desc->iConfiguration;
+
+		offset = desc->bLength;
+
+		while (offset < length) {
+			if (buf[offset + 1] == USB_DT_INTERFACE) {
+				struct usb_interface_descriptor *if_desc =
+					(struct usb_interface_descriptor *)
+					(buf + offset);
+
+				if (if_desc->iInterface > udc->top_str_id)
+					udc->top_str_id = if_desc->iInterface;
+			}
+
+			offset += buf[offset];
+		}
+
+		if ((length % 8) == 0) {
+			/* BIOS can't handle descriptors with size multiple
+			   of xfer size */
+			length += 1;
+			/* desc->wTotalLength = cpu_to_le16(length); */
+		}
+
+		/* BIOS can only handle configuration 1,
+		   so make sure the config nr is 1 */
+		desc->bConfigurationValue = 1;
+
+		c67x00_ll_write_mem_le16(udc->sie->dev,
+					 SIEx_CONF_DESC_LOC(udc->sie->sie_num),
+					 req->req.buf, length);
+
+		/* Write vector address to SW interrupt */
+		c67x00_ll_set_configuration_descriptor_location(
+			udc->sie, SIEx_CONF_DESC_LOC(udc->sie->sie_num));
+
+		/* String descriptors start behind configuration descriptor */
+		udc->string_desc_addr =
+			SIEx_CONF_DESC_LOC(udc->sie->sie_num) + length;
+
+		/* Make sure the address is even */
+		if (udc->string_desc_addr & 0x01)
+			udc->string_desc_addr++;
+
+		/* Write string descriptor vector address */
+		c67x00_ll_set_string_descriptor_location(
+			udc->sie, udc->string_desc_addr);
+
+		retval = 1;
+		break;
+	}
+
+	case USB_DT_STRING:
+		/* Write string descriptor */
+		c67x00_ll_write_mem_le16(udc->sie->dev, udc->string_desc_addr,
+					 req->req.buf, req->req.length);
+
+		/* set address to end of this descriptor */
+		udc->string_desc_addr += req->req.length;
+
+		retval = 1;
+		break;
+	}
+
+	return retval;
+}
+
+/*
+ * done - retire a request; caller blocked irqs
+ */
+static void c67x00_udc_done(struct c67x00_udc_ep *ep,
+			    struct c67x00_request *req, int status)
+{
+	int stopped = ep->stopped;
+
+	list_del_init(&req->queue);
+
+	if (likely(req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+/*
+	if (status && status != -ESHUTDOWN)
+		DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length);
+*/
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+	req->req.complete(&ep->ep, &req->req);
+	ep->stopped = stopped;
+}
+
+/*----------- UDC send/receive functions -------------------------------------*/
+
+static void c67x00_udc_start_io_irq(struct c67x00_udc_ep *ep)
+{
+	struct c67x00_sie *sie = ep->udc->sie;
+	struct c67x00_request *req =
+		list_entry(ep->queue.next, struct c67x00_request, queue);
+
+	if (ep->is_ep_in)
+		c67x00_ll_susb_start_send(sie, ep->ep_num,
+					  req->req.buf, req->req.length);
+	else
+		c67x00_ll_susb_start_receive(sie, ep->ep_num, req->req.length);
+}
+
+static void c67x00_udc_io_work(struct work_struct *_udc)
+{
+	int i = 0;
+	struct c67x00_udc *udc =
+	    container_of(_udc, struct c67x00_udc, io_work);
+
+	for (i = 0; i < C67X00_MAX_NB_END_POINTS; i++) {
+		struct c67x00_udc_ep *ep = &udc->ep[i];
+		if (ep->start_io) {
+			ep->start_io = 0;
+			c67x00_udc_start_io_irq(ep);
+		}
+	}
+}
+
+static void c67x00_udc_schedule_io_irq(struct c67x00_udc_ep *ep)
+{
+	ep->start_io = 1;
+
+	/* start work queue */
+	schedule_work(&ep->udc->io_work);
+}
+
+static void c67x00_udc_done_irq(struct c67x00_udc_ep *ep, int status)
+{
+	struct c67x00_request *req;
+	struct c67x00_sie *sie = ep->udc->sie;
+	int result;
+
+	result = c67x00_ll_susb_get_transfer_status(sie, ep->ep_num);
+	if (result < 0) {
+		dev_err(sie_dev(sie), "udc_done_irq error (%d)\n", result);
+		return;
+	}
+
+	if (unlikely(list_empty(&ep->queue)))
+		return;
+
+	req = list_entry(ep->queue.next, struct c67x00_request, queue);
+
+	req->req.actual = req->req.length - result;
+
+	if (!ep->is_ep_in && ep->ep_num != 0)
+		c67x00_ll_susb_receive(sie, ep->ep_num,
+				       req->req.buf, req->req.actual);
+
+	c67x00_udc_done(ep, req, 0);
+	if (!list_empty(&ep->queue) && !ep->stopped)
+		/* restart io req */
+		c67x00_udc_schedule_io_irq(ep);
+}
+
+/* -------------------------------------------------------------------------- */
+/* endpoints */
+
+static const char *c67x00_ep_name[C67X00_MAX_NB_END_POINTS] = {
+	"ep0", "ep1out-bulk", "ep2in-bulk", "ep3", "ep4", "ep5", "ep6", "ep7"
+};
+
+
+/* -------------------------------------------------------------------------- */
+/* ep opts */
+
+/*
+ * empties entire endpoint queue
+ */
+static void c67x00_nuke_ep(struct c67x00_udc_ep *ep, int status)
+{
+	ep->stopped = 1;
+
+	while (!list_empty(&ep->queue)) {
+		struct c67x00_request *req =
+			list_entry(ep->queue.next, struct c67x00_request,
+				   queue);
+		c67x00_udc_done(ep, req, status);
+	}
+}
+
+static int c67x00_ep_enable(struct usb_ep *_ep,
+			    const struct usb_endpoint_descriptor *desc)
+{
+	struct c67x00_udc_ep *ep;
+	struct c67x00_sie *sie;
+	u16 maxpacket;
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+	sie = ep->udc->sie;
+
+	maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+
+	c67x00_ll_set_device_ep_status(sie, ep->ep_num, 0x0000);
+
+	if (desc->bEndpointAddress & USB_DIR_IN) {
+		ep->is_ep_in = 1;
+		c67x00_ll_set_ep_ctrl_reg(sie, ep->ep_num,
+					  EP_ENABLE | DIR_SEL_IN);
+		c67x00_ll_set_ep_packet_size_reg(sie, ep->ep_num, maxpacket);
+	} else {
+		ep->is_ep_in = 0;
+		c67x00_ll_set_ep_ctrl_reg(sie, ep->ep_num, EP_ENABLE);
+		c67x00_ll_set_ep_packet_size_reg(sie, ep->ep_num, maxpacket);
+	}
+
+	ep->enable = 1;
+	ep->stopped = 0;
+	ep->ep.maxpacket = maxpacket;
+
+	return 0;
+}
+
+static int c67x00_ep_disable(struct usb_ep *_ep)
+{
+	unsigned long flags;
+	struct c67x00_udc_ep *ep;
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+
+	dev_dbg(sie_dev(ep->udc->sie), "ep_disable %s\n", _ep->name);
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+
+	ep->enable = 0;
+	ep->stopped = 1;
+
+	c67x00_nuke_ep(ep, -ESHUTDOWN);
+
+	spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+	return 0;
+}
+
+
+struct usb_request *c67x00_ep_alloc_request(struct usb_ep *_ep,
+					    gfp_t gfp_flags)
+{
+	struct c67x00_request *req;
+
+	req = kzalloc(sizeof(struct c67x00_request), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+static void c67x00_ep_free_request(struct usb_ep *_ep,
+				   struct usb_request *_req)
+{
+	struct c67x00_request *req = NULL;
+	struct c67x00_udc_ep *ep;
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+	dev_dbg(sie_dev(ep->udc->sie), "free_request %s\n", _ep->name);
+
+	req = container_of(_req, struct c67x00_request, req);
+
+	if (_req)
+		kfree(req);
+}
+
+static int c67x00_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+			   gfp_t gfp_flags)
+{
+	struct c67x00_udc_ep *ep;
+	struct c67x00_request *req;
+	unsigned long flags;
+	int request = 0;
+	struct c67x00_udc *dev;
+
+	req = container_of(_req, struct c67x00_request, req);
+	if (unlikely
+	    (!_req || !_req->complete || !_req->buf
+	     || !list_empty(&req->queue))) {
+		printk(KERN_WARNING "bad params\n");
+		return -EINVAL;
+	}
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+	if (unlikely(!_ep)) {
+		dev_warn(sie_dev(ep->udc->sie), "bad ep\n");
+		return -EINVAL;
+	}
+
+	dev = ep->udc;
+	if (unlikely
+	    (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+		dev_warn(sie_dev(ep->udc->sie), "bogus device state\n");
+		return -ESHUTDOWN;
+	}
+
+	if (ep->ep_num == 0) {
+		/* The gadget driver returns the descriptors through this way */
+		if (!c67x00_udc_parse_descriptor(dev, req)) {
+			req->req.actual = req->req.length;
+			return -EINVAL;
+		} else {
+			req->req.status = 0;
+			req->req.actual = req->req.length;
+			req->req.complete(&ep->ep, &req->req);
+			return 0;
+		}
+
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* Start I/O queue if the list was empty */
+	if (list_empty(&ep->queue) && !ep->stopped)
+		request = 1;
+
+	/* Add the request to the queue of the endpoint */
+	list_add_tail(&req->queue, &ep->queue);
+
+	if (request)
+		c67x00_udc_schedule_io_irq(ep);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+
+static int c67x00_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct c67x00_udc_ep *ep;
+	struct c67x00_request *req;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+	if (!_ep || ep->ep_num == 0)
+		return -EINVAL;
+
+	dev_dbg(sie_dev(ep->udc->sie), "dequeue %s\n", _ep->name);
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore(&ep->udc->lock, flags);
+		return -EINVAL;
+	}
+
+	c67x00_udc_done(ep, req, -ECONNRESET);
+
+	spin_unlock_irqrestore(&ep->udc->lock, flags);
+	return 0;
+}
+
+
+
+static int c67x00_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	printk(KERN_WARNING "c67x00-udc : ep set_halt %s\n", _ep->name);
+	return -ENODEV;
+}
+
+static void c67x00_ep_fifo_flush(struct usb_ep *_ep)
+{
+	printk(KERN_WARNING "c67x00-udc : ep fifo_flush %s\n", _ep->name);
+}
+
+
+static const struct usb_ep_ops c67x00_ep_ops = {
+	.enable = c67x00_ep_enable,
+	.disable = c67x00_ep_disable,
+
+	.alloc_request = c67x00_ep_alloc_request,
+	.free_request = c67x00_ep_free_request,
+
+	.queue = c67x00_ep_queue,
+	.dequeue = c67x00_ep_dequeue,
+
+	.set_halt = c67x00_ep_set_halt,
+	.fifo_flush = c67x00_ep_fifo_flush,
+};
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_udc_msg_received(struct c67x00_sie *sie, u16 msg)
+{
+	struct c67x00_udc *udc = sie->private_data;
+	u16 EPx_msg_mask = /*SUSB_EP0_MSG | */ SUSB_EP1_MSG
+		| SUSB_EP2_MSG
+		| SUSB_EP3_MSG
+		| SUSB_EP4_MSG
+		| SUSB_EP5_MSG
+		| SUSB_EP6_MSG
+		| SUSB_EP7_MSG;
+
+	if ((msg & EPx_msg_mask) != 0) {
+		int i, mask = 0x01;
+
+		for (i = 0; i < C67X00_MAX_NB_END_POINTS; i++, mask <<= 1)
+			if (msg & mask)
+				c67x00_udc_done_irq(&udc->ep[i], 0);
+	}
+
+	if (msg & SUSB_RST_MSG) {
+		int i;
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_RST_MSG\n", msg);
+
+		for (i = 0; i < C67X00_MAX_NB_END_POINTS; i++) {
+			struct c67x00_udc_ep *ep = &udc->ep[i];
+			if (i != 0 && ep->enable) {
+				ep->stopped = 1;
+				c67x00_nuke_ep(ep, -ESHUTDOWN);
+			}
+		}
+		if (udc->driver && udc->driver->disconnect)
+			udc->driver->disconnect(&udc->gadget);
+	}
+
+	if (msg & SUSB_SOF_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_SOF_MSG\n", msg);
+	}
+
+	if (msg & SUSB_CFG_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_CFG_MSG\n", msg);
+		/* the c67x00 BIOS only supports 1 configuration,
+		   so it must be configuration 1 */
+		c67x00_udc_set_configuration(sie, udc->config_nr);
+	}
+
+	if (msg & SUSB_SUS_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_SUS_MSG\n", msg);
+	}
+
+	if (msg & SUSB_ID_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_ID_MSG\n", msg);
+	}
+
+	if (msg & SUSB_VBUS_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_VBUS_MSG\n", msg);
+	}
+}
+
+
+/*
+ * This function is called from the interrupt handler in c67x00-drv.c
+ */
+static void c67x00_udc_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
+{
+	u16 device_status;
+
+	if (msg)
+		c67x00_udc_msg_received(sie, msg);
+
+	device_status = c67x00_ll_usb_get_status(sie);
+
+	if (int_status & SOFEOP_FLG(sie->sie_num))
+		c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
+
+	if (int_status & RESET_FLG(sie->sie_num)) {
+		dev_info(sie_dev(sie), "sie%d : reset IRQ\n",
+			 sie->sie_num);
+
+		/* Handle reset here */
+		c67x00_ll_usb_clear_status(sie, RESET_IRQ_FLG);
+	}
+
+	if (int_status & DONE_FLG(sie->sie_num))
+		dev_info(sie_dev(sie), "sie%d : done IRQ -> "
+			 "device status 0x%04X\n",
+			 sie->sie_num, device_status);
+}
+
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct c67x00_udc *udc = &controller;
+	int i, retval;
+
+	if (!driver
+/*		|| driver->speed < USB_SPEED_FULL*/
+	    || !driver->bind || !driver->setup) {
+
+		printk(KERN_ERR
+		       "c67x00 : invalid gadget driver provided\n");
+		return -EINVAL;
+	}
+
+
+	spin_lock(&udc->lock);
+	if (!udc->sie || udc->driver) {
+		spin_unlock(&udc->lock);
+		return -EBUSY;
+	}
+
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+	udc->config_nr = 1;
+	udc->top_str_id = 0;
+	device_add(&udc->gadget.dev);
+
+	driver->driver.bus = NULL;
+
+	dev_dbg(sie_dev(udc->sie), "Binding %s to SIE%d\n",
+		 driver->function, udc->sie->sie_num);
+
+	retval = driver->bind(&udc->gadget);
+	if (retval) {
+		dev_warn(sie_dev(udc->sie), "Driver bind failed\n");
+		goto error;
+	}
+
+	/* retrieve descriptors from gadget and program them in device */
+	udc->driver->setup(&udc->gadget,
+			   (struct usb_ctrlrequest *)
+			   get_descriptor_device);
+	udc->driver->setup(&udc->gadget,
+			   (struct usb_ctrlrequest *)
+			   get_descriptor_config);
+
+	for (i = 0; i <= udc->top_str_id; i++) {
+		get_descriptor_string[2] = i;
+		udc->driver->setup(&udc->gadget,
+				   (struct usb_ctrlrequest *)
+				   get_descriptor_string);
+	}
+
+	spin_unlock(&udc->lock);
+
+	/* enable device */
+	c67x00_ll_susb_init(udc->sie);
+
+	return 0;
+
+error :
+	udc->driver = NULL;
+	udc->gadget.dev.driver = NULL;
+	device_del(&udc->gadget.dev);
+
+	spin_unlock(&udc->lock);
+
+	return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct c67x00_udc *udc = &controller;
+
+	printk(KERN_WARNING "c67x00-udc : usb_gadget_unregister_driver\n");
+
+	spin_lock(&udc->lock);
+	if (udc->driver != driver) {
+		spin_unlock(&udc->lock);
+		return -EINVAL;
+	}
+
+	udc->driver = NULL;
+
+	driver->unbind(&udc->gadget);
+	device_del(&udc->gadget.dev);
+
+	c67x00_ll_susb_disable(udc->sie);
+
+	spin_unlock(&udc->lock);
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/* -------------------------------------------------------------------------- */
+
+int c67x00_udc_probe(struct c67x00_sie *sie)
+{
+	struct c67x00_udc *udc = &controller;
+	unsigned long flags;
+	int i;
+
+	if (udc->sie) {
+		dev_err(sie_dev(sie),
+			"Only 1 peripheral port supported, check sie_config\n");
+		return -EBUSY;
+	}
+
+	spin_lock_init(&udc->lock);
+	INIT_WORK(&udc->io_work, c67x00_udc_io_work);
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+	udc->gadget.ep0 = &udc->ep[0].ep;
+	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+	for (i = 0; i < C67X00_MAX_NB_END_POINTS; i++) {
+		struct c67x00_udc_ep *ep = &udc->ep[i];
+		if (i != 0) {
+			INIT_LIST_HEAD(&udc->ep[i].ep.ep_list);
+			list_add_tail(&udc->ep[i].ep.ep_list,
+				      &udc->gadget.ep_list);
+		}
+		ep->ep.name = c67x00_ep_name[i];
+		ep->ep.ops = &c67x00_ep_ops;
+		ep->enable = 0;
+		ep->start_io = 0;
+		if (i == 0)
+			ep->ep.maxpacket = 8;
+		else
+			/* Size is set when endpoint is enabled */
+			ep->ep.maxpacket = 512;
+		ep->ep_num = i;
+		ep->udc = udc;
+		INIT_LIST_HEAD(&ep->queue);
+	}
+
+	udc->sie = sie;
+	udc->gadget.dev.parent = &sie->dev->pdev->dev;
+	device_initialize(&udc->gadget.dev);
+
+	spin_lock_irqsave(&sie->lock, flags);
+	sie->private_data = udc;
+	sie->irq = c67x00_udc_irq;
+	spin_unlock_irqrestore(&sie->lock, flags);
+
+	return 0;
+}
+
+void c67x00_udc_remove(struct c67x00_sie *sie)
+{
+	struct c67x00_udc *udc = sie->private_data;
+
+	if (!udc) {
+		dev_err(sie_dev(sie), "No udc found!\n");
+		return;
+	}
+
+	/* gadget driver must not be registered */
+	BUG_ON(udc->driver != NULL);
+
+	spin_lock(&udc->lock);
+	sie->private_data = NULL;
+	udc->sie = NULL;
+	spin_unlock(&udc->lock);
+}
Index: linux-2.6/drivers/usb/c67x00/c67x00-udc.h
===================================================================
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/c67x00-udc.h
@@ -0,0 +1,48 @@
+/*
+ * c67x00-udc.h: Cypress C67X00 USB device controller
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple device controller drivers inside the linux kernel.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#ifndef _USB_C67X00_UDC_H
+#define _USB_C67X00_UDC_H
+
+#include <linux/kernel.h>
+
+#include "c67x00.h"
+
+#ifdef CONFIG_USB_GADGET_C67X00
+/* Functions used by drv */
+int c67x00_udc_probe(struct c67x00_sie *sie);
+void c67x00_udc_remove(struct c67x00_sie *sie);
+#else
+static inline int c67x00_udc_probe(struct c67x00_sie *sie)
+{
+	printk(KERN_ERR "udc requested but CONFIG_USB_GADGET_C67X00 "
+	       "not enabled!\n");
+	return -ENODEV;
+}
+
+static inline void c67x00_udc_remove(struct c67x00_sie *sie)
+{
+}
+#endif				/* CONFIG_USB_GADGET_C67X00 */
+
+#endif				/* _USB_C67X00_UDC_H */
Index: linux-2.6/drivers/usb/c67x00/c67x00-drv.c
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/c67x00-drv.c
+++ linux-2.6/drivers/usb/c67x00/c67x00-drv.c
@@ -42,6 +42,7 @@
 
 #include "c67x00.h"
 #include "c67x00-hcd.h"
+#include "c67x00-udc.h"
 
 static void c67x00_probe_sie(struct c67x00_sie *sie,
 			     struct c67x00_device *dev, int sie_num)
@@ -56,6 +57,11 @@
 		c67x00_hcd_probe(sie);
 		break;
 
+	case C67X00_SIE_PERIPHERAL_A:
+	case C67X00_SIE_PERIPHERAL_B:
+		c67x00_udc_probe(sie);
+		break;
+
 	case C67X00_SIE_UNUSED:
 		dev_info(sie_dev(sie),
 			 "Not using SIE %d as requested\n", sie->sie_num);
@@ -76,6 +82,11 @@
 		c67x00_hcd_remove(sie);
 		break;
 
+	case C67X00_SIE_PERIPHERAL_A:
+	case C67X00_SIE_PERIPHERAL_B:
+		c67x00_udc_remove(sie);
+		break;
+
 	default:
 		break;
 	}
Index: linux-2.6/drivers/usb/c67x00/c67x00-ll-hpi.c
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/c67x00-ll-hpi.c
+++ linux-2.6/drivers/usb/c67x00/c67x00-ll-hpi.c
@@ -296,6 +296,11 @@
 	return rc;
 }
 
+static u16 c67x00_get_comm_reg(struct c67x00_device *dev, u16 nr)
+{
+	return hpi_read_word(dev, COMM_R(nr));
+}
+
 /* -------------------------------------------------------------------------- */
 /* Host specific functions */
 
@@ -372,6 +377,207 @@
 }
 
 /* -------------------------------------------------------------------------- */
+void c67x00_ll_susb_init(struct c67x00_sie *sie)
+{
+	struct c67x00_device *dev = sie->dev;
+	struct c67x00_lcp_int_data data;
+	u16 addr;
+	int rc;
+
+	/* The BIOS SUSB_INIT_INT handler for some reason is hardcoded to only
+	   enable peripheral support for port A. Relocate the routine to RAM
+	   and patch out that instruction (mov [r10-0xe],[r8]) */
+	addr = hpi_read_word(dev, SUSB_INIT_INT_LOC);
+
+	/* already patched? */
+	if (addr != CY_UDC_BIOS_REPLACE_BASE) {
+		u16 buf[64]; /* should be plenty for the handler */
+		int i;
+
+		c67x00_ll_read_mem_le16(dev, addr, buf, sizeof(buf));
+
+		/* patch it */
+		for (i = 0; i < (ARRAY_SIZE(buf)-1); i++) {
+			if ((buf[i] == cpu_to_le16(0x0432))
+			    && (buf[i+1] == cpu_to_le16(0xfff2))) {
+				buf[i] = buf[i+1] = 0; /* nop */
+				break;
+			}
+		}
+
+		if (i >= ARRAY_SIZE(buf))
+			dev_warn(sie_dev(sie), "BIOS code not recognized, "
+				 "port B may not be available\n");
+
+		c67x00_ll_write_mem_le16(dev, CY_UDC_BIOS_REPLACE_BASE,
+					 buf, sizeof(buf));
+		hpi_write_word(dev, SUSB_INIT_INT_LOC,
+			       CY_UDC_BIOS_REPLACE_BASE);
+	}
+
+	hpi_clear_bits(dev, HPI_IRQ_ROUTING_REG,
+		       SOFEOP_TO_HPI_EN(sie->sie_num));
+	hpi_set_bits(dev,
+		     HPI_IRQ_ROUTING_REG,
+		     SOFEOP_TO_CPU_EN(sie->sie_num)
+		     | RESUME_TO_HPI_ENABLE(sie->sie_num)
+		     | ID_TO_HPI_ENABLE | VBUS_TO_HPI_ENABLE);
+
+	hpi_set_bits(dev,
+		     DEVICE_N_IRQ_EN_REG(sie->sie_num),
+		     SOF_EOP_TMOUT_IRQ_EN | ID_IRQ_EN | VBUS_IRQ_EN);
+
+	hpi_clear_bits(dev,
+		       USB_CTL_REG(sie->sie_num),
+		       SOF_EOP_EN(0) | SOF_EOP_EN(1));
+
+	if (sie->mode == C67X00_SIE_PERIPHERAL_A)
+		hpi_write_word(dev, DEVICE_N_PORT_SEL(sie->sie_num),  0x0000);
+	else
+		hpi_write_word(dev, DEVICE_N_PORT_SEL(sie->sie_num),  0x4000);
+
+	data.regs[1] = 0; /* full speed */
+	data.regs[2] = sie->sie_num + 1;
+	rc = c67x00_comm_exec_int(dev, SUSB_INIT_INT, &data);
+
+	if ((hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
+		dev_warn(sie_dev(sie),
+			 "SIE %d not set to peri mode\n", sie->sie_num);
+
+	BUG_ON(rc); /* No return path for error code; crash spectacularly */
+
+	hpi_set_bits(dev,
+		     DEVICE_N_IRQ_EN_REG(sie->sie_num),
+		     SOF_EOP_TMOUT_IRQ_EN | ID_IRQ_EN | VBUS_IRQ_EN);
+
+	dev_info(sie_dev(sie),
+		 "Peripheral USB device setup on SIE%d\n",
+		 sie->sie_num);
+}
+
+void c67x00_ll_susb_disable(struct c67x00_sie *sie)
+{
+	hpi_write_word(sie->dev, DEVICE_N_IRQ_EN_REG(sie->sie_num), 0);
+	hpi_write_word(sie->dev, USB_CTL_REG(sie->sie_num),  0x0000);
+}
+
+void c67x00_ll_set_ep_ctrl_reg(struct c67x00_sie *sie, int ep_num, u16 val)
+{
+	hpi_write_word(sie->dev,
+		       DEVICE_N_ENDPOINT_N_CTL_REG(sie->sie_num, ep_num), val);
+}
+
+void c67x00_ll_set_ep_packet_size_reg(struct c67x00_sie *sie, int ep_num,
+				      u16 val)
+{
+	/* This undocumented register needs to be set to the packet size
+	   Normally the BIOS sets this correctly when it is able to parse
+	   the configuration descriptor correctly */
+	hpi_write_word(sie->dev,
+		       (DEVICE_N_ENDPOINT_N_CTL_REG(sie->sie_num, ep_num)
+			+ 0x0A), val);
+}
+
+u16 c67x00_ll_get_device_ep_status(struct c67x00_sie *sie, int ep)
+{
+	return hpi_read_word(sie->dev,
+			     DEVICE_N_ENDPOINT_N_STAT_REG(sie->sie_num, ep));
+}
+
+void c67x00_ll_set_device_ep_status(struct c67x00_sie *sie,
+				    int ep, u16 value)
+{
+	hpi_write_word(sie->dev,
+		       DEVICE_N_ENDPOINT_N_STAT_REG(sie->sie_num, ep),
+		       value);
+}
+
+void c67x00_ll_set_device_descriptor_location(struct c67x00_sie *sie,
+					      u16 address)
+{
+	hpi_write_word(sie->dev, SUSBx_DEV_DESC_VEC(sie->sie_num), address);
+}
+
+void c67x00_ll_set_configuration_descriptor_location(struct c67x00_sie *sie,
+						     u16 address)
+{
+	hpi_write_word(sie->dev, SUSBx_CONF_DESC_VEC(sie->sie_num), address);
+}
+
+void c67x00_ll_set_string_descriptor_location(struct c67x00_sie *sie,
+					      u16 address)
+{
+	hpi_write_word(sie->dev, SUSBx_STRING_DESC_VEC(sie->sie_num), address);
+}
+
+int c67x00_ll_susb_start_send(struct c67x00_sie *sie, int ep,
+			      void *data, int len)
+{
+	u16 header[4];
+	struct c67x00_lcp_int_data regs;
+
+	c67x00_ll_write_mem_le16(sie->dev, CY_UDC_REQ_BUFFER_ADDR(ep),
+				 data, len);
+
+	header[0] = 0;
+	header[1] = cpu_to_le16(CY_UDC_REQ_BUFFER_ADDR(ep));
+	header[2] = cpu_to_le16(len);
+	header[3] = 0;
+
+	c67x00_ll_write_mem_le16(sie->dev, CY_UDC_REQ_HEADER_ADDR(ep), header,
+				 sizeof(header));
+
+	regs.regs[0] = 0;
+	regs.regs[1] = ep;
+	regs.regs[8] = CY_UDC_REQ_HEADER_ADDR(ep);
+
+	return c67x00_comm_exec_int(sie->dev, SUSBx_SEND_INT(sie->sie_num),
+				    &regs);
+}
+
+int c67x00_ll_susb_start_receive(struct c67x00_sie *sie, int ep, int len)
+{
+	u16 header[4];
+	struct c67x00_lcp_int_data regs;
+
+	header[0] = 0;
+	header[1] = cpu_to_le16(CY_UDC_REQ_BUFFER_ADDR(ep));
+	header[2] = cpu_to_le16(len);
+	header[3] = 0;
+
+	c67x00_ll_write_mem_le16(sie->dev, CY_UDC_REQ_HEADER_ADDR(ep), header,
+				 sizeof(header));
+
+	regs.regs[0] = 0;
+	regs.regs[1] = ep;
+	regs.regs[8] = CY_UDC_REQ_HEADER_ADDR(ep);
+
+	return c67x00_comm_exec_int(sie->dev, SUSBx_RECEIVE_INT(sie->sie_num),
+				    &regs);
+}
+
+int c67x00_ll_susb_get_transfer_status(struct c67x00_sie *sie, int ep)
+{
+	u16 header[4];
+	u16 result = c67x00_get_comm_reg(sie->dev, 0);
+
+	if (result)
+		return -result;
+
+	c67x00_ll_read_mem_le16(sie->dev, CY_UDC_REQ_HEADER_ADDR(ep),
+				header, sizeof(header));
+	/* nr of bytes not transferred */
+	return le16_to_cpu(header[2]);
+}
+
+void c67x00_ll_susb_receive(struct c67x00_sie *sie, int ep,
+			    void *data, int len)
+{
+	c67x00_ll_read_mem_le16(sie->dev, CY_UDC_REQ_BUFFER_ADDR(ep),
+				data, len);
+}
+
+/* -------------------------------------------------------------------------- */
 
 void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
 {
Index: linux-2.6/drivers/usb/c67x00/c67x00.h
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/c67x00.h
+++ linux-2.6/drivers/usb/c67x00/c67x00.h
@@ -283,6 +283,27 @@
 void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie);
 void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port);
 
+/* Slave specific functions */
+void c67x00_ll_susb_init(struct c67x00_sie *sie);
+void c67x00_ll_susb_disable(struct c67x00_sie *sie);
+void c67x00_ll_set_ep_ctrl_reg(struct c67x00_sie *sie, int ep_num, u16 val);
+void c67x00_ll_set_ep_packet_size_reg(struct c67x00_sie *sie, int ep_num,
+				      u16 val);
+u16 c67x00_ll_get_device_ep_status(struct c67x00_sie *sie, int ep);
+void c67x00_ll_set_device_ep_status(struct c67x00_sie *sie, int ep, u16 value);
+void c67x00_ll_set_device_descriptor_location(struct c67x00_sie *sie,
+					      u16 address);
+void c67x00_ll_set_configuration_descriptor_location(struct c67x00_sie *sie,
+						     u16 address);
+void c67x00_ll_set_string_descriptor_location(struct c67x00_sie *sie,
+					      u16 address);
+int c67x00_ll_susb_start_send(struct c67x00_sie *sie, int ep,
+			      void *data, int len);
+int c67x00_ll_susb_start_receive(struct c67x00_sie *sie, int ep, int len);
+int c67x00_ll_susb_get_transfer_status(struct c67x00_sie *sie, int ep);
+void c67x00_ll_susb_receive(struct c67x00_sie *sie, int ep,
+			    void *data, int len);
+
 /* Called by c67x00_irq to handle lcp interrupts */
 void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status);
 
Index: linux-2.6/drivers/usb/c67x00/Makefile
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/Makefile
+++ linux-2.6/drivers/usb/c67x00/Makefile
@@ -4,6 +4,9 @@
 
 ccflags-$(CONFIG_USB_DEBUG)		+= -DDEBUG
 
-obj-$(CONFIG_USB_C67X00_HCD)		+= c67x00.o
+obj-$(CONFIG_USB_C67X00_DRV)		+= c67x00.o
 
-c67x00-objs := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o
+c67x00-y				+= c67x00-drv.o c67x00-ll-hpi.o
+
+c67x00-$(CONFIG_USB_C67X00_HCD)		+= c67x00-hcd.o c67x00-sched.o
+c67x00-$(CONFIG_USB_GADGET_C67X00)	+= c67x00-udc.o
Index: linux-2.6/drivers/usb/gadget/Kconfig
===================================================================
--- linux-2.6.orig/drivers/usb/gadget/Kconfig
+++ linux-2.6/drivers/usb/gadget/Kconfig
@@ -335,6 +335,13 @@
 	depends on USB_GADGET_AT91
 	default USB_GADGET
 
+config USB_GADGET_C67X00
+	boolean "Cypress C67X00 Gadget support"
+	depends on USB_C67X00_DRV
+	select USB_GADGET_SELECTED
+	help
+	  This enables the gadget functionality of the Cypress C67X00.
+
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
 	depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
Index: linux-2.6/drivers/usb/gadget/gadget_chips.h
===================================================================
--- linux-2.6.orig/drivers/usb/gadget/gadget_chips.h
+++ linux-2.6/drivers/usb/gadget/gadget_chips.h
@@ -147,6 +147,12 @@
 #define	gadget_is_m66592(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_C67X00
+#define	gadget_is_c67x00(g)	!strcmp("c67x00_udc", (g)->name)
+#else
+#define	gadget_is_c67x00(g)	0
+#endif
+
 
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
@@ -212,5 +218,7 @@
 		return 0x20;
 	else if (gadget_is_m66592(gadget))
 		return 0x21;
+	else if (gadget_is_c67x00(gadget))
+		return 0x22;
 	return -ENOENT;
 }
Index: linux-2.6/drivers/usb/host/Kconfig
===================================================================
--- linux-2.6.orig/drivers/usb/host/Kconfig
+++ linux-2.6/drivers/usb/host/Kconfig
@@ -4,19 +4,6 @@
 comment "USB Host Controller Drivers"
 	depends on USB
 
-config USB_C67X00_HCD
-	tristate "Cypress C67x00 HCD support"
-	depends on USB
-	help
-	  The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
-	  host/peripheral/OTG USB controllers.
-
-	  Enable this option to support this chip in host controller mode.
-	  If unsure, say N.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called c67x00.
-
 config USB_EHCI_HCD
 	tristate "EHCI HCD (USB 2.0) support"
 	depends on USB && USB_ARCH_HAS_EHCI
Index: linux-2.6/drivers/usb/Makefile
===================================================================
--- linux-2.6.orig/drivers/usb/Makefile
+++ linux-2.6/drivers/usb/Makefile
@@ -17,7 +17,7 @@
 obj-$(CONFIG_USB_U132_HCD)	+= host/
 obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 
-obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
+obj-$(CONFIG_USB_C67X00_DRV)	+= c67x00/
 
 obj-$(CONFIG_USB_ACM)		+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
Index: linux-2.6/drivers/usb/Kconfig
===================================================================
--- linux-2.6.orig/drivers/usb/Kconfig
+++ linux-2.6/drivers/usb/Kconfig
@@ -97,6 +97,8 @@
 
 source "drivers/usb/host/Kconfig"
 
+source "drivers/usb/c67x00/Kconfig"
+
 source "drivers/usb/class/Kconfig"
 
 source "drivers/usb/storage/Kconfig"
Index: linux-2.6/drivers/usb/c67x00/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/Kconfig
@@ -0,0 +1,21 @@
+#
+# Cypress C67x00 USB controller
+#
+config USB_C67X00_DRV
+	tristate "Cypress C67x00 support"
+	# only allowed to be =y if both USB!=m and USB_GADGET!=m
+	depends on (!USB && USB_GADGET) || (!USB_GADGET && USB) || (USB && USB_GADGET)
+	help
+	  The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
+	  host/peripheral USB controllers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called c67x00.
+
+config USB_C67X00_HCD
+	bool "Cypress C67X00 HCD support"
+	depends on USB && USB_C67X00_DRV
+	default y
+	help
+	  Enable this option to support the Cypress C67x00 in host
+	  controller mode.
Index: linux-2.6/drivers/usb/c67x00/c67x00-hcd.h
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/c67x00-hcd.h
+++ linux-2.6/drivers/usb/c67x00/c67x00-hcd.h
@@ -112,8 +112,21 @@
  * Functions used by c67x00-drv
  */
 
+#ifdef CONFIG_USB_C67X00_HCD
 int c67x00_hcd_probe(struct c67x00_sie *sie);
 void c67x00_hcd_remove(struct c67x00_sie *sie);
+#else
+static inline int c67x00_hcd_probe(struct c67x00_sie *sie)
+{
+	printk(KERN_ERR "hcd requested but CONFIG_USB_C67X00_HCD "
+	       "not enabled!\n");
+	return -ENODEV;
+}
+
+static inline void c67x00_hcd_remove(struct c67x00_sie *sie)
+{
+}
+#endif				/* CONFIG_USB_C67X00_HCD */
 
 /* ---------------------------------------------------------------------
  * Transfer Descriptor scheduling functions

--
Bye, Peter Korsgaard

^ permalink raw reply

* [patch v10 0/4] Cypress c67x00 (EZ-Host/EZ-OTG) support
From: Peter Korsgaard @ 2008-02-21 15:34 UTC (permalink / raw)
  To: dbrownell, linux-usb, linuxppc-dev, grant.likely, stern, greg

The Cypress c67x00 (EZ-Host/EZ-OTG) controllers are multi-role low/fullspeed
USB controllers. This patch series implements a HCD driver and shows the
work-in-progress status of a gadget driver.

I believe patch 1..3 are ready, and I would like to see them queued up for
mainline.

Changes since v9:
 - Put Kconfig in alphabetical order, use ccflags-$(CONFIG_USB_DEBUG)
   (feedback from David)

Changes since v8:
 - checkpatch.pl fixes (__FUNCTION__ -> __func__, indent)

Changes since v7:
 - Moved dummy hcd probe/remove functions for conditional hcd support into
   udc patch.
 - Moved usb_disabled() check into c67x00_hcd_probe().
 - Moved c67x00_get_comm_reg() to udc patch as it is only needed for gadget
   support.

Changes since v6:
 - Addressed David and Alan's comments (removed done list + tasklet)

Changes since v5:
 - Merged c67x00_ll_{get,set}_siemsg() into c67x00_ll_fetch_siemsg().
 - Fix for interrupt race condition at probe time (reported by Grant)

Changes since v4:
 - Addressed Grant's comments (c67x00_dev->c67x00_hcd_dev, label indent)
 - Moved c67x00_ll_set_ep_{ctrl,packet_size}_reg() to patch 4 as they are
   only needed for gadget support.

Changes since v3:
- Lots of cleanups: checkpatch, interrupt handling, c67x00_ prefixes, ..
- The dummy platform_device's created per serial engine are gone.
- Gadget driver (WIP)

--
Bye, Peter Korsgaard

^ permalink raw reply

* Re: MPC8641D PCI-Express error
From: Jon Loeliger @ 2008-02-21 15:58 UTC (permalink / raw)
  To: Marco Stornelli; +Cc: Timur Tabi, LinuxPPC-Embedded
In-Reply-To: <47BD9ACE.1090003@coritel.it>

Marco Stornelli wrote:
> 
> When I try to read some register from my FPGA (virtex5) I have this bus
> error:


Hmmm....  OK, so if we've eliminated PCI-E as a source
for this issue, it really must be in the Virtex support
somewhere then.  Unfortunately, I know nothing about those,
and am not going to be much direct help there.

Sorry.

jdl


> Machine check in kernel mode.
> Caused by (from SRR1=149030): Transfer error ack signal
> Oops: Machine check, sig: 7 [#1]
> PREEMPT SMP NR_CPUS=2
> Modules linked in: virtex5
> LTT NESTING LEVEL : 0
> NIP: F108019C LR: F1080198 CTR: 00000001
> REGS: c044dd60 TRAP: 0200   Not tainted      (2.6.18-mpc8641d_hpcn)
> MSR: 00149030 <EE,ME,IR,DR>  CR: 22000222  XER: 00000000
> TASK = c20e9990[568] 'insmod' THREAD: c044c000 CPU: 0
> GPR00: F1080198 C044DE10 C20E9990 0000002E 80000000 FFFFFFFF 00008000
> 00002EA3
> GPR08: C20E9990 00000000 C04C0220 C044C000 22000222 1001956C 00000000
> 00000000
> GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> 00000000
> GPR24: 3000EAA0 7FD6FDC0 00000000 C045FCC0 F107E594 F10A0000 00000000
> C2036000
> NIP [F108019C] virtex5_probe+0x130/0x1c4 [virtex5]
> LR [F1080198] virtex5_probe+0x12c/0x1c4 [virtex5]
> Call Trace:
> [C044DE10] [F1080198] virtex5_probe+0x12c/0x1c4 [virtex5] (unreliable)
> [C044DE30] [C01D2A58] pci_device_probe+0x84/0xbc
> [C044DE50] [C0213754] driver_probe_device+0x60/0x118
> [C044DE70] [C0213890] __driver_attach+0x84/0x88
> [C044DE90] [C02130F4] bus_for_each_dev+0x58/0x94
> [C044DEC0] [C02135D4] driver_attach+0x24/0x34
> [C044DED0] [C0212AC8] bus_add_driver+0x88/0x164
> [C044DEF0] [C021397C] driver_register+0x70/0xb8
> [C044DF00] [C01D284C] __pci_register_driver+0x64/0x98
> [C044DF10] [F1080030] init_module+0x30/0x6c [virtex5]
> [C044DF20] [C004CBFC] sys_init_module+0xc8/0x25c
> [C044DF40] [C0011358] ret_from_syscall+0x0/0x38
> --- Exception: c00 at 0xff6de0c
>     LR = 0x10000de4
> Instruction dump:
> 40820060 3c60f108 3863cea0 48000311 807f0238 3c800001 48000395 7c7d1b78
> 3c60f108 3863ced4 480002f5 809d0000 <3c60f108> 3863cf04 480002e5 3c60f108

^ permalink raw reply

* Re: Block devices
From: Christoph Hellwig @ 2008-02-21 16:48 UTC (permalink / raw)
  To: David H. Lynch Jr.; +Cc: linux-fsdevel, linux-mtd, linuxppc-embedded
In-Reply-To: <47BD22D0.9060008@dlasys.net>

On Thu, Feb 21, 2008 at 02:05:52AM -0500, David H. Lynch Jr. wrote:
>     Can I boot an initramfs kernel without a block device ?

Yes.

>     Can I write a filesystem driver for a flash device that does not
> require a block device ?

Yes.

>     Are their any examples of something even close ?

For that particular flash case there's just jffs2 in the kernel tree,
with some more flash filesystems under development.  You can of
course have network and in-memory filesystems aswell.

^ permalink raw reply

* Re: Problems with plb_temac+hard_temac+2.6.24rc3
From: A. Nolson @ 2008-02-21 17:10 UTC (permalink / raw)
  To: Rick Moleres; +Cc: linuxppc-embedded
In-Reply-To: <20080221022651.1383190008A@mail125-sin.bigfish.com>

That is correct. I changed to hard temac 3.00.a and everything seems to 
work perfectly now.

Thank you very much for your help,

/A

Rick Moleres wrote:
> Try using hard_temac_v3_00_a with the ML403 board.  There's an
> incompatibility (posted previously on this list) with PHY access.  This
> could be causing the strange behavior you're seeing.
>
> -Rick
>
> -----Original Message-----
> From: linuxppc-embedded-bounces+moleres=xilinx.com@ozlabs.org
> [mailto:linuxppc-embedded-bounces+moleres=xilinx.com@ozlabs.org] On
> Behalf Of A. Nolson
> Sent: Wednesday, February 20, 2008 8:33 AM
> To: linuxppc-embedded@ozlabs.org
> Subject: Problems with plb_temac+hard_temac+2.6.24rc3
>
> Hi,
>
>  I am working with a ML403 platform and I have my kernel 2.6.24rc3 
> perfectly running on it. Almost everything seems to work but the 
> ethernet. I am using the IP cores that come with the EDK 9.1sp2 ( 
> plb_emac 3.00a + hard_temac 3.00b). The weird thing arises when I try to
>
> bring up the interface and use it. If I do "ifconfig eth0 up" the 
> interface shows up but, strangely, it eithers not receives or send 
> packets. I will explain myself, if I assing an IP manually and try to 
> connect to another worksatation within the network ( by pinging from 
> just one of the sides  for example ) the interface seems only to send or
>
> receive packets , but generallty not both at the same time ( I can see 
> this through the evolution of the Rx/Tx bytes in ifconfig). The only few
>
> times that both tx/rx work at the same time is when I do (ifconfig eth0 
> down and ifconfig eth0 up), but this only works sporadically and only  
> for around a second or less.
>
> This is what I get after the first "ifconfig eth0 up":
> [  293.258765] eth0: XTemac: Options: 0xb8f2
>
> [  295.253048] eth0: XTemac: speed set to 10Mb/s
>
> [  295.256042] eth0: XTemac: Send Threshold = 16, Receive Threshold = 2
>
> [  295.256095] eth0: XTemac: Send Wait bound = 1, Receive Wait bound = 1
>
> [  297.252047] eth0: XTemac: PHY Link carrier lost.
>
> [  299.251657] eth0: XTemac: PHY Link carrier restored.
>
>
> and this after some ifconfig up/down:
>
> [  293.258765] eth0: XTemac: Options: 0xb8f2
>
> [  295.253048] eth0: XTemac: speed set to 10Mb/s
>
> [  295.256042] eth0: XTemac: Send Threshold = 16, Receive Threshold = 2
>
> [  295.256095] eth0: XTemac: Send Wait bound = 1, Receive Wait bound = 1
>
> [  297.252047] eth0: XTemac: PHY Link carrier lost.
>
> [  299.251657] eth0: XTemac: PHY Link carrier restored.
>
> [  438.159833] eth0: XTemac: Options: 0xb8f2
>
> [  440.154122] eth0: XTemac: speed set to 1000Mb/s
>
> [  440.157316] eth0: XTemac: Send Threshold = 16, Receive Threshold = 2
>
> [  440.157369] eth0: XTemac: Send Wait bound = 1, Receive Wait bound = 1
>
> [  442.153739] eth0: XTemac: PHY Link carrier lost.
>
> [  511.255518] eth0: XTemac: Options: 0xb8f2
>
> [  513.249808] eth0: XTemac: speed set to 10Mb/s
>
> [  513.252729] eth0: XTemac: Send Threshold = 16, Receive Threshold = 2
>
> [  513.252784] eth0: XTemac: Send Wait bound = 1, Receive Wait bound = 1
>
> [  515.249462] eth0: XTemac: PHY Link carrier restored.
>
> [  992.441619] eth0: XTemac: Options: 0xb8f2
>
> [  994.435904] eth0: XTemac: speed set to 1000Mb/s
>
> [  994.438786] eth0: XTemac: Send Threshold = 16, Receive Threshold = 2
>
> [  994.438839] eth0: XTemac: Send Wait bound = 1, Receive Wait bound = 1
>
> [  996.435460] eth0: XTemac: PHY Link carrier lost.
>
> [ 1099.850622] eth0: XTemac: Options: 0xb8f2
>
> [ 1101.844907] eth0: XTemac: speed set to 10Mb/s
>
> [ 1101.847816] eth0: XTemac: Send Threshold = 16, Receive Threshold = 2
>
> [ 1101.847868] eth0: XTemac: Send Wait bound = 1, Receive Wait bound = 1
>
> [ 1103.844479] eth0: XTemac: PHY Link carrier restored.
>
> [ 1180.024979] eth0: XTemac: Options: 0xb8f2
>
> [ 1182.019263] eth0: XTemac: speed set to 1000Mb/s
>
> [ 1182.022265] eth0: XTemac: Send Threshold = 16, Receive Threshold = 2
>
> [ 1182.022316] eth0: XTemac: Send Wait bound = 1, Receive Wait bound = 1
>
> [ 1184.018815] eth0: XTemac: PHY Link carrier lost.
>
>
> It also seems to negotiate wrongly the speed since my network is
> 100Mb/s.
>
> This is my dmesg before "ifconfig eth0 up":
>
> [    0.000000] Linux version 2.6.24-rc3-gd7ed933b-dirty (ios@xxx) (gcc 
> versio
> ion 4.0.0 (DENX ELDK 4.1 4.0.0)) #17 Mon Feb 18 11:52:47 CET 
> 2008               [
> [    0.000000] Xilinx ML403 Reference System (Virtex-4 
> FX)                      [
> [    0.000000] Entering add_active_range(0, 0, 16384) 0 entries of 256 
> used     [
> [    0.000000] Zone PFN 
> ranges:                                                 [
> [    0.000000]   DMA             0 ->    
> 16384                                  [
> [    0.000000]   Normal      16384 ->    
> 16384                                  [
> [    0.000000]   HighMem     16384 ->    
> 16384                                  [
> [    0.000000] Movable zone start PFN for each 
> node                             [
> [    0.000000] early_node_map[1] active PFN 
> ranges                              [
> [    0.000000]     0:        0 ->    
> 16384                                      [
> [    0.000000] On node 0 totalpages: 
> 16384                                      [
> [    0.000000]   DMA zone: 128 pages used for 
> memmap                            [
> [    0.000000]   DMA zone: 0 pages 
> reserved                                     [
> [    0.000000]   DMA zone: 16256 pages, LIFO 
> batch:3                            [
> [    0.000000]   Normal zone: 0 pages used for 
> memmap                           [
> [    0.000000]   HighMem zone: 0 pages used for 
> memmap                          [
> [    0.000000]   Movable zone: 0 pages used for 
> memmap                          [
> [    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  
> Total pages
> es: 
> 16256
>
> [
> [    0.000000] Kernel command line: console=ttyS0,57600 root=/dev/xsa2 
> rw init=/sb
> sbin/init
>
> [
> [    0.000000] Xilinx INTC #0 at 0x41200000 mapped to 
> 0xFDFFE000                [
> [    0.000000] PID hash table entries: 256 (order: 8, 1024 
> bytes)               [
> [    0.000189] Console: colour dummy device 
> 80x25                               [
> [    0.000632] Dentry cache hash table entries: 8192 (order: 3, 32768 
> bytes)    [
> [    0.001411] Inode-cache hash table entries: 4096 (order: 2, 16384 
> bytes)     [
> [    0.015628] Memory: 61312k available (2744k kernel code, 780k data, 
> 116k init,
> , 0k 
> highmem)
>
> [
> [    0.015942] SLUB: Genslabs=11, HWalign=32, Order=0-1, MinObjects=4, 
> CPUs=1, Nod
> odes=1
>
> [
> [    0.015988] Calibrating delay loop... 199.47 BogoMIPS 
> (lpj=997376)           [
> [    0.210274] Mount-cache hash table entries: 
> 512                              [
> [    0.214569] net_namespace: 64 
> bytes                                          [
> [    0.220610] NET: Registered protocol family 
> 16                               [
> [    0.268325] NET: Registered protocol family 
> 2                                [
> [    0.350699] IP route cache hash table entries: 1024 (order: 0, 4096 
> bytes)   [
> [    0.353529] TCP established hash table entries: 2048 (order: 2, 16384
>
> bytes) [
> [    0.353862] TCP bind hash table entries: 2048 (order: 1, 8192 
> bytes)         [
> [    0.354067] TCP: Hash tables configured (established 2048 bind 
> 2048)         [
> [    0.354107] TCP reno 
> registered                                              [
> [    0.381445] sysctl table check failed: /kernel/l2cr .1.31 Missing 
> strategy   [
> [    0.381529] Call 
> Trace:                                                      [
> [    0.381556] [c3c11e80] [c0008380] show_stack+0x4c/0x174 
> (unreliable)         [
> [    0.381653] [c3c11eb0] [c0037170] 
> set_fail+0x50/0x68                         [
> [    0.381735] [c3c11ed0] [c00377f8] 
> sysctl_check_table+0x670/0x6bc             [
> [    0.381804] [c3c11f10] [c003780c] 
> sysctl_check_table+0x684/0x6bc             [
> [    0.381871] [c3c11f50] [c0024e7c] 
> register_sysctl_table+0x5c/0xac            [
> [    0.381953] [c3c11f70] [c034ab68] 
> register_ppc_htab_sysctl+0x18/0x2c         [
> [    0.382040] [c3c11f80] [c034484c] 
> kernel_init+0xc8/0x284                     [
> [    0.382103] [c3c11ff0] [c0004b18] 
> kernel_thread+0x44/0x60                    [
> [    0.442249] Installing knfsd (copyright (C) 1996 
> okir@monad.swb.de).         [
> [    0.447391] JFS: nTxBlock = 479, nTxLock = 
> 3832                              [
> [    0.450534] SGI XFS with ACLs, large block numbers, no debug 
> enabled         [
> [    0.466636] io scheduler noop 
> registered                                     [
> [    0.466687] io scheduler anticipatory 
> registered                             [
> [    0.466722] io scheduler deadline 
> registered                                 [
> [    0.467224] io scheduler cfq registered 
> (default)                            [
> [    1.069672] Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ 
> sharing di
> disabled
>
> [
> [    1.078357] serial8250.0: ttyS0 at MMIO 0x40401003 (irq = 3) is a 
> 16550A     [
> [    1.078443] console [ttyS0] 
> enabled                                          [
> [    1.621990] RAMDISK driver initialized: 16 RAM disks of 4096K size 
> 1024 blocksi
> size
>
> [
> [    1.644429] loop: module 
> loaded                                              [
> [    1.651930] xsysace xsysace.0: Xilinx SystemACE revision 
> 1.0.12              [
> [    1.664582] xsysace xsysace.0: capacity: 1019088 
> sectors                     [
> [    1.675836]  xsa: xsa1 xsa2 
> xsa3                                             [
> [    1.688906] Xilinx SystemACE device driver, 
> major=254                        [
> [    1.700197] nbd: registered device at major 
> 43                               [
> [    1.728380] XTemac: using sgDMA 
> mode.                                        [
> [    1.735840] XTemac: using TxDRE 
> mode                                         [
> [    1.743198] XTemac: using RxDRE 
> mode                                         [
> [    1.750455] XTemac: buffer descriptor size: 32768 
> (0x8000)                   [
> [    1.762007] XTemac: (buffer_descriptor_init) phy: 0x3d98000, virt: 
> 0xff100000,
> , size: 
> 0x8000
> [
> [    1.785641] eth%d: XTemac: No PHY detected.  Assuming a PHY at 
> address 0     [
> [    1.799277] eth0: Dropping NETIF_F_SG since no checksum 
> feature.             [
> [    1.814696] eth0: Xilinx TEMAC #0 at 0x81200000 mapped to 0xC5060000,
>
> irq=0  [
> [    1.828792] eth0: XTemac id 1.0f, block id 5, type 
> 8                         [
> [    1.840200] NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c 
> $Revision: 1
>  1.41 
> $
> [
> [    1.856295] INFTL: inftlcore.c $Revision: 1.19 $, inftlmount.c 
> $Revision: 1.18
> 8 
> $
>
> [
> [    1.872015] SSFDC read-only Flash Translation 
> layer                          [
> [    1.885404] i8042.c: No controller 
> found.                                    [
> [    1.895700] mice: PS/2 mouse device common for all 
> mice                      [
> [    1.908819] i2c /dev entries 
> driver                                          [
> [    1.917372] TCP cubic 
> registered                                             [
> [    1.924238] NET: Registered protocol family 
> 1                                [
> [    1.933271] NET: Registered protocol family 
> 17                               [
> [    1.944649] RPC: Registered udp transport 
> module.                            [
> [    1.954206] RPC: Registered tcp transport 
> module.                            [
> [    4.575003] kjournald starting.  Commit interval 5 
> seconds                   [
> [    4.586220] EXT3-fs warning: maximal mount count reached, running 
> e2fsck is rec
> ecommended
>
> [
> [    4.641727] EXT3 FS on xsa2, internal 
> journal                                [
> [    4.650587] EXT3-fs: recovery 
> complete.                                      [
> [    4.697624] EXT3-fs: mounted filesystem with ordered data 
> mode.              [
> [    4.709702] VFS: Mounted root (ext3 
> filesystem).                             [
> [    4.719390] Freeing unused kernel memory: 116k 
> init                          
> ba                                                              
>
> Any idea of what it can be?
>
> Thanks in advance!
>
> /A
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
>
>
>   

^ permalink raw reply

* make zImage.initrd failure (was: Re: [PATCH v4] [POWERPC] bootwrapper: build multiple cuImages)
From: Geert Uytterhoeven @ 2008-02-21 17:22 UTC (permalink / raw)
  To: Grant Likely; +Cc: Linux/PPC Development, Hiroaki Fuse
In-Reply-To: <20080206181833.13239.70510.stgit@trillian.secretlab.ca>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 4818 bytes --]

	Hi Grant,

On Wed, 6 Feb 2008, Grant Likely wrote:
> From: Grant Likely <grant.likely@secretlab.ca>
> 
> Currently, the kernel uses CONFIG_DEVICE_TREE to wrap a kernel image
> with a fdt blob which means for any given configuration only one dts
> file can be selected and so support for only one board can be built
> 
> This patch moves the selection of the default .dts file out of the kernel
> config and into the bootwrapper makefile.  The makefile chooses which
> images to build based on the kernel config and the dts source file
> name is taken directly from the image name.  For example "cuImage.ebony"
> will use "ebony.dts" as the device tree source file.
> 
> In addition, this patch allows a specific image to be requested from the
> command line by adding "cuImage.%" and "treeImage.%" targets to the list
> of valid built targets in arch/powerpc/Makefile.  This allows the default
> dts selection to be overridden.
> 
> Another advantage to this change is it allows a single defconfig to be
> supplied for all boards using the same chip family and only differing in
> the device tree.
> 
> Important note: This patch adds two new zImage targets; zImage.dtb.% and
> zImage.dtb.initrd.% for zImages with embedded dtb files.  Currently
> there are 5 platforms which require this: ps3, ep405, mpc885ads, ep88xc,
> adder875-redboot and ep8248e.  This patch *changes the zImage filenames*
> for those platforms.  ie. 'zImage.ps3' is now 'zImage.dtb.ps3'.
> 
> This new zImage.dtb targets were added so that the .dts file could be
> part of the dependancies list for building them.
> 
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> 
> ---
> v4: removed mpc837x_mds and mpc8313erdb cuimages and changed mpc885ads to
> a cuImage
> 
> v3: I think this patch is complete.  Renamed zImage.dtb.% targets to
> zImage-dtb.% to avoid make choosing the wrong rule if the dts file is missing.
> 
> v2: This version fixes some bugs and adds new zImage.dtb and
> zImage.initrd.dtb targets.
> 
> v1: Please review and comment.  I have not exhaustively tested this patch
> and I'm sure to have missed some boards.  However, I think the concept
> is sound and will be a good change.

Fuse-san discovered we can no longer do `make zImage.initrd' when building for
PS3:

|   WRAP    arch/powerpc/boot/zImage.initrd-dtb.ps3
| ppu-ld: arch/powerpc/boot/initrd-dtb.ps3.o: No such file: No such file or directory
| make[3]: *** [arch/powerpc/boot/zImage.initrd-dtb.ps3] Error 1
| make[2]: *** [zImage.initrd] Error 2
| make[1]: *** [sub-make] Error 2
| make: *** [all] Error 2

It can easily be reproduced using `make ps3_defconfig; make zImage.initrd'.

There seem to be two problems:

 1. Before this patch, the generated build target was `zImage.initrd.ps3'.
    After this patch, the generated build target is `zImage.initrd-dtb.ps3'.
    Now `initrd-dtb.ps3' is passed to the boot wrapper as the `platform'
    parameter, which of course no longer matches the `ps3' test case in the
    boot wrapper script.
    The patch below works around this problem, but I don't think it's the
    proper fix.

diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index c317815..aec4414 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -182,7 +182,7 @@ cuboot*)
         ;;
     esac
     ;;
-ps3)
+*ps3)
     platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o"
     lds=$object/zImage.ps3.lds
     gzip=

>  # Don't put the ramdisk on the pattern rule; when its missing make will try
>  # the pattern rule with less dependencies that also matches (even with the
>  # hard dependency listed).
> -$(obj)/zImage.initrd.%: vmlinux $(wrapperbits) $(dts)
> -	$(call if_changed,wrap,$*,$(dts),,$(obj)/ramdisk.image.gz)
> +$(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
> +	$(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
>  
> -$(obj)/zImage.%: vmlinux $(wrapperbits) $(dts)
> -	$(call if_changed,wrap,$*,$(dts))
> +$(obj)/zImage.%: vmlinux $(wrapperbits)
> +	$(call if_changed,wrap,$*)

  2. The generated build target `zImage.initrd-dtb.ps3' matches both rules,
     and of course the wrong one (the second one) is chosen by make, causing
     the ramdisk image not to be included.

With kind regards,

Geert Uytterhoeven
Software Architect

Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium

Phone:    +32 (0)2 700 8453
Fax:      +32 (0)2 700 8622
E-mail:   Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/

Sony Network and Software Technology Center Europe
A division of Sony Service Centre (Europe) N.V.
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium
VAT BE 0413.825.160 · RPR Brussels
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619

^ permalink raw reply related

* Xilinx Temac link detect
From: khollan @ 2008-02-21 17:36 UTC (permalink / raw)
  To: linuxppc-embedded


Hi 

Is there a good way to detect if the ethernet link is active at boot time,
so I can decided to setup the dchp and other network required stuff in an
init script.  When I try to setup this stuff and the cable is disconnected
it hangs.

Thanks

Kevin
-- 
View this message in context: http://www.nabble.com/Xilinx-Temac-link-detect-tp15616042p15616042.html
Sent from the linuxppc-embedded mailing list archive at Nabble.com.

^ permalink raw reply

* Re: TLB Miss booting linux kernel on ppc 405
From: Ricardo Ayres Severo @ 2008-02-21 17:50 UTC (permalink / raw)
  To: David Baird; +Cc: linuxppc-embedded
In-Reply-To: <440abda90802201347w3945c53dhf47ffd0380aa01aa@mail.gmail.com>

Hi David,

I rebuilt the design in EDK 9.2i and problem persisted. The only
difference is the registers are not zeroing anymore. No exception is
thrown, and the system still hangs at memset_io. I'm running out of
options.
It is possible to boot Linux on Virtex-II, isn't?

Thanks,

On Wed, Feb 20, 2008 at 7:47 PM, David Baird <dhbaird@gmail.com> wrote:
> Hi Ricardo,
>
>
>  On Feb 20, 2008 2:29 PM, Ricardo Ayres Severo <severo.ricardo@gmail.com> wrote:
>  > I didn't solve the problem yet. I'm having problems with the memset_io
>  > in early_init and am studying if the SDRAM is initializing right.
>  > Any progress I'll send to the list.
>
>  It sounds suspiciously like you might be having this problem:
>
>     http://www.nabble.com/Problem-booting-Linux-2.6-on-Virtex-4-td14795525.html
>     "Things start to go obviously wrong after early_init calls memset to
>     clear the .bss section."
>
>  I don't know what the cause of the problem was, but the symptom is
>  that different memory regions were aliased onto each other (it was
>  like an address bit wasn't working or something funny was happening
>  with the cache ... but only in virtual mode).  The problem was fixed
>  after rebuilding the design in EDK 9.2i.  I don't know what caused the
>  problem originally though.
>
>  Let us know if you get this resolved or have more questions...  I
>  might not be able answer, but hopefully someone can help.
>
>  -David
>



-- 
Ricardo Ayres Severo <severo.ricardo@gmail.com>

^ permalink raw reply

* RE: Xilinx  PowerPC
From: Stephen Neuendorffer @ 2008-02-21 17:50 UTC (permalink / raw)
  To: David H. Lynch Jr., Grant Likely, linuxppc-embedded
In-Reply-To: <47BD212B.6090809@dlasys.net>



> -----Original Message-----
> From: linuxppc-embedded-bounces+stephen=3Dneuendorffer.name@ozlabs.org
[mailto:linuxppc-embedded-
> bounces+stephen=3Dneuendorffer.name@ozlabs.org] On Behalf Of David H.
Lynch Jr.
> Sent: Wednesday, February 20, 2008 10:59 PM
> To: Grant Likely; linuxppc-embedded
> Subject: Xilinx PowerPC
>=20
>=20
>     So when you have Xilinx under powerpc working, do we pull it from
your
>     git tree or the xilinx one ?
>=20
>     Will there be an announcement ?
>=20
>     How about a one paragraph getting started guide to moving a xilinx
> ppc bsp to
>     xilinx powerpc.
>=20
>     Like  ?
>=20
>     step 1).
>              Generate a dts - gen-mhs-devicetree ?
>              And pass it to through your boot loader to Linux ?

http://git.xilinx.com/gen-mhs-devtree.git contains two utilities for
generating device trees from EDK projects.  The older option is a python
script, originally written by Grant.  The newer (and probably more
mature at this point) option is an EDK BSP generator for u-boot,
originally written by Michal Simek.  Preferably this gets passed from a
uboot, although it's also possible to compile it into the kernel.
Currently, the uboot option is somewhat annoying because there's not a
good surefire way for getting uboot up and running on an EDK design.
(Unfortunately, the EDK BSP generator is incomplete, and the uboot
support for virtex needs some work to get it integrated as well).

>     Step 2).
>              the code in arch/powerpc/???? is the devicetree equvalent
to
>              arch/ppc/platforms/4xx/xilinx_ml410.c
http://git.xilinx.com/linux-2.6-xlnx.git contains a preliminary stab at
the bootcode for Virtex.  I've been using this for a while with
ARCH=3Dpowerpc.  There isn't really much need for board specific =
platform
code: This should (I think) be handled by the device tree.  All of this
is still pretty preliminary at the moment however.  The big problem with
the boot code in the Xilinx tree is that you need to be able to allocate
memory in order to parse the device tree in order to figure out how much
memory you have.  I just haven't rewritten the code to use libfdt, which
can query the device tree without memory allocation yet.  Grant has a
slightly different scheme in his tree, but it works as well.  Generally
I've been more focused on avoiding u-boot, whereas Grant has been using
u-boot exclusively, I think.

>     Step 3).
>              device drivers need to change initialization/setup from
>              ???? to ???
All the xilinx drivers in mainline and most of the ones in the
git.xilinx.com tree export both platform device and of_device
interfaces.  You should be able to look at any of them to figure out a
good way of adding of_device support to a driver.  the ll_temac is by
far the most complex instance of this, which has to do some non-trivial
traversal of the device tree to discover the information it needs about
it's interface to memory.

So, the short answer is, you might be able to get it to work today, but
the code isn't in shape for mainline yet.

Steve

^ permalink raw reply

* Re: initramfs problem - /init file
From: raul.moreno @ 2008-02-21 16:05 UTC (permalink / raw)
  To: dhlii; +Cc: linuxppc-embedded
In-Reply-To: <47BD9936.2000400@dlasys.lcl>


Hi Dave,

I have just figured out the problem... an stupid error... By mistake I =
took
the filesystem compiled to intel instead to ppc. I guess I forgot to as=
sign
the right cross-compile toolchain. So the microprocessor can't execute =
the
init file.

Now it works.
Anyway thank you for your time.


Ra=FAl Moreno



"David H. Lynch Jr." <dhlii@dlasys.lcl>
"David H. Lynch Jr."
21/02/2008 16:31
Por favor, responda a dhlii
                                                                       =
                                                
 Para:   raul.moreno@telvent.abengoa.com                               =
                                                
                                                                       =
                                                
 cc:     linuxppc-embedded <linuxppc-embedded@ozlabs.org>              =
                                                
                                                                       =
                                                
 Asunto: Re: initramfs problem - /init file                            =
                                                
                                                                       =
                                                





raul.moreno@telvent.abengoa.com wrote:
> Hello Dave,
>
> thanks for your answer. I agree with you, the easy way is to assign t=
he
> rootfs directory. I gave the filesystem as a cpio file because it is =
the
> same (the kernel takes the rootfs and converts it to a cpio format), =
but
> the compilation is faster. Anyway, although now I do as you said, I s=
till
> get the error:
> "Failed to execute /init
> Kernel panic - not syncing: No init found.  Try passing init=3D optio=
n to
> kernel."
> I can't understand why it happens. I check the permission of /init an=
d
> /sbin/init and everything seems to me OK.
>
> Any idea?
>
    I have had the same problem.
    Things I can remember:
          Permissions,
          console setup,
          watch out for symbolic links to init.
          Also is your init and executable or  script ?
          I think you get this failure if ANYTHING goes wrong exec'ing
init.
             Like - it found init but could not execute a shell.
             or the shell required a library it could not find.
          Or something is not quite right with your Virtual memory -
            Linux exec's by forcing chained page faults.

       One thing I tried was a simple "hello world" in ppc assembler -
no libraries,
       and named it /init. When it succeeded I was able to narrow my
problem down..
       Then tried a "hello world" in C with a static library, then
dynamic, then ...
       Basically building more and more complex /init's until I isolate=
d
what was failing.






> Ra=FAl Moreno
>
>
>
>


--
Dave Lynch
     DLA Systems
Software Development:
Embedded Linux
717.627.3770                    dhlii@dlasys.net
http://www.dlasys.net
fax: 1.253.369.9244                                               Cell:=

1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too=

numerous to list.

"Any intelligent fool can make things bigger and more complex... It tak=
es a
touch of genius - and a lot of courage to move in the opposite directio=
n."
Albert Einstein

=

^ permalink raw reply

* Re: TLB Miss booting linux kernel on ppc 405
From: David Baird @ 2008-02-21 18:00 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <5ee408090802210950t498b9752meab2b91d2a13191c@mail.gmail.com>

On Thu, Feb 21, 2008 at 10:50 AM, Ricardo Ayres Severo
<severo.ricardo@gmail.com> wrote:
>  I rebuilt the design in EDK 9.2i and problem persisted. The only
>  difference is the registers are not zeroing anymore. No exception is
>  thrown, and the system still hangs at memset_io. I'm running out of
>  options.
>  It is possible to boot Linux on Virtex-II, isn't?

Yes, it is possible.  I have a Virtex-II Pro with Linux running on it
although I didn't configure it myself (it is one of those Black Dog
computers).  I work with Virtex-4s right now.

Can you try a reference design for the Virtex-II perhaps?

Can you comment out memset_io and write your own version of it (which
you can insert debug statements into)?

When/where in memset are things breaking?  What is the nature of the
breaking?  Can you get your serial terminal to print out hex values
(for memory locations, memory values, etc.)?

^ permalink raw reply

* Re: TLB Miss booting linux kernel on ppc 405
From: David Baird @ 2008-02-21 18:04 UTC (permalink / raw)
  To: linuxppc-embedded, Robert Woodworth
In-Reply-To: <1203542646.4812.38.camel@PisteOff>

Hi Robert,

On Wed, Feb 20, 2008 at 2:24 PM, Robert Woodworth
<rwoodworth@securics.com> wrote:
>  I'm under the suspicion that the PLB is issuing an error when switching
>  to virtual mode and that there is either a timing/synthesis error or a
>  fundamental error with the way the FPGA is getting synthesized with the
>  PLB.

Can you offer a suggestion how I can check to see if the PLB is
issuing an error (a good application note for me to read or anything)?
 I was having a similar problem in virtual mode on one of my systems,
and I might be able to see also if I am having a problem with the PLB
bus.

-David

^ permalink raw reply

* [PATCH] [POWERPC] Fix zImage-dtb.initrd build error
From: Grant Likely @ 2008-02-21 18:57 UTC (permalink / raw)
  To: Geert.Uytterhoeven, linuxppc-dev; +Cc: miltonm, paulus, Hiroaki_Fuse

From: Grant Likely <grant.likely@secretlab.ca>

The pattern substitution rules were failing when used with zImage-dtb
targets.  if zImage-dtb.initrd was selected, the pattern substitution
would generate "zImage.initrd-dtb" instead of "zImage-dtb.initrd" which
caused the build to fail.

This patch renames zImage-dtb to dtbImage to avoid the problem entirely.
By not using the zImage prefix then is no potential for namespace
collisions.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

---
Note to reviewers.  Please consider this change carefully.  I saw two
options for fixing this bug;
1) rework the pattern substitution to handle zImage-dtb correctly
2) avoid using the zImage prefix

I chose option 2 because it avoids increasing the complexity of the
pattern substitution code for generating initrd names.  However, doing
so will have an impact on distributors because it changes the name of
the generated image.  If this is a problem for anyone, or if you have
a better name suggestion than "dtbImage", then please speak up.

Cheers,
g.
---

 arch/powerpc/Makefile      |    2 +-
 arch/powerpc/boot/Makefile |   18 ++++++++++--------
 2 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 1c6ce35..ab5cfe8 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -155,7 +155,7 @@ all: zImage
 
 CPPFLAGS_vmlinux.lds	:= -Upowerpc
 
-BOOT_TARGETS = zImage zImage.initrd uImage treeImage.% cuImage.%
+BOOT_TARGETS = zImage zImage.initrd uImage zImage% dtbImage% treeImage.% cuImage.%
 
 PHONY += $(BOOT_TARGETS)
 
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 63d07cc..d57a67d 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -186,7 +186,7 @@ quiet_cmd_wrap	= WRAP    $@
 image-$(CONFIG_PPC_PSERIES)		+= zImage.pseries
 image-$(CONFIG_PPC_MAPLE)		+= zImage.pseries
 image-$(CONFIG_PPC_IBM_CELL_BLADE)	+= zImage.pseries
-image-$(CONFIG_PPC_PS3)			+= zImage-dtb.ps3
+image-$(CONFIG_PPC_PS3)			+= dtbImage.ps3
 image-$(CONFIG_PPC_CELLEB)		+= zImage.pseries
 image-$(CONFIG_PPC_CHRP)		+= zImage.chrp
 image-$(CONFIG_PPC_EFIKA)		+= zImage.chrp
@@ -205,7 +205,7 @@ image-$(CONFIG_DEFAULT_UIMAGE)		+= uImage
 #
 
 # Board ports in arch/powerpc/platform/40x/Kconfig
-image-$(CONFIG_EP405)			+= zImage-dtb.ep405
+image-$(CONFIG_EP405)			+= dtbImage.ep405
 image-$(CONFIG_WALNUT)			+= treeImage.walnut
 
 # Board ports in arch/powerpc/platform/44x/Kconfig
@@ -220,9 +220,9 @@ image-$(CONFIG_WARP)			+= cuImage.warp
 # Board ports in arch/powerpc/platform/8xx/Kconfig
 image-$(CONFIG_PPC_MPC86XADS)		+= cuImage.mpc866ads
 image-$(CONFIG_PPC_MPC885ADS)		+= cuImage.mpc885ads
-image-$(CONFIG_PPC_EP88XC)		+= zImage-dtb.ep88xc
+image-$(CONFIG_PPC_EP88XC)		+= dtbImage.ep88xc
 image-$(CONFIG_PPC_ADDER875)		+= cuImage.adder875-uboot \
-					   zImage-dtb.adder875-redboot
+					   dtbImage.adder875-redboot
 
 # Board ports in arch/powerpc/platform/52xx/Kconfig
 image-$(CONFIG_PPC_LITE5200)		+= cuImage.lite5200 cuImage.lite5200b
@@ -230,7 +230,7 @@ image-$(CONFIG_PPC_LITE5200)		+= cuImage.lite5200 cuImage.lite5200b
 # Board ports in arch/powerpc/platform/82xx/Kconfig
 image-$(CONFIG_MPC8272_ADS)		+= cuImage.mpc8272ads
 image-$(CONFIG_PQ2FADS)			+= cuImage.pq2fads
-image-$(CONFIG_EP8248E)			+= zImage-dtb.ep8248e
+image-$(CONFIG_EP8248E)			+= dtbImage.ep8248e
 
 # Board ports in arch/powerpc/platform/83xx/Kconfig
 image-$(CONFIG_MPC832x_MDS)		+= cuImage.mpc832x_mds
@@ -268,7 +268,8 @@ endif
 
 initrd-  := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-))
 initrd-y := $(patsubst zImage%, zImage.initrd%, \
-		$(patsubst treeImage%, treeImage.initrd%, $(image-y)))
+		$(patsubst dtbImage%, dtbImage.initrd%, \
+		$(patsubst treeImage%, treeImage.initrd%, $(image-y))))
 initrd-y := $(filter-out $(image-y), $(initrd-y))
 targets	+= $(image-y) $(initrd-y)
 
@@ -283,10 +284,11 @@ $(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
 $(obj)/zImage.%: vmlinux $(wrapperbits)
 	$(call if_changed,wrap,$*)
 
-$(obj)/zImage-dtb.initrd.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
+# dtbImage% - a dtbImage is a zImage with an embedded device tree blob
+$(obj)/dtbImage.initrd.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
 	$(call if_changed,wrap,$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz)
 
-$(obj)/zImage-dtb.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
+$(obj)/dtbImage.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
 	$(call if_changed,wrap,$*,$(dtstree)/$*.dts)
 
 # This cannot be in the root of $(src) as the zImage rule always adds a $(obj)

^ permalink raw reply related

* Re: Xilinx PowerPC
From: Grant Likely @ 2008-02-21 19:02 UTC (permalink / raw)
  To: Stephen Neuendorffer; +Cc: linuxppc-embedded
In-Reply-To: <20080221175025.7817BBD8057@mail91-sin.bigfish.com>

On Thu, Feb 21, 2008 at 10:50 AM, Stephen Neuendorffer
<stephen.neuendorffer@xilinx.com> wrote:
>  >     Step 2).
>  >              the code in arch/powerpc/???? is the devicetree equvalent
>  to
>  >              arch/ppc/platforms/4xx/xilinx_ml410.c
>  http://git.xilinx.com/linux-2.6-xlnx.git contains a preliminary stab at
>  the bootcode for Virtex.  I've been using this for a while with
>  ARCH=powerpc.  There isn't really much need for board specific platform
>  code: This should (I think) be handled by the device tree.  All of this
>  is still pretty preliminary at the moment however.  The big problem with
>  the boot code in the Xilinx tree is that you need to be able to allocate
>  memory in order to parse the device tree in order to figure out how much
>  memory you have.  I just haven't rewritten the code to use libfdt, which
>  can query the device tree without memory allocation yet.  Grant has a
>  slightly different scheme in his tree, but it works as well.  Generally
>  I've been more focused on avoiding u-boot, whereas Grant has been using
>  u-boot exclusively, I think.

Actually, I'm not using u-boot at all.  I've reworked the 'raw' image
target to use libfdt and properly initialize the cache and stuff.
I'll be merging it in the .26 merge window.

Cheers,
g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: TLB Miss booting linux kernel on ppc 405
From: Robert Woodworth @ 2008-02-21 19:12 UTC (permalink / raw)
  To: David Baird; +Cc: linuxppc-embedded
In-Reply-To: <440abda90802211004h3833ed00ke1cdc1257e2b0379@mail.gmail.com>

I'm no expert but....

I did configure my device with the DCR enabled and connected the PLBv46
DCR to the PPC.  In the TLB miss ISR I read the PLB registers and the
MCSR I *DID* notice that the PLB error registers were set.

I added some asm code to read MCSR (see Xilinx UG011.pdf, page 213) and
I also added the asm code to read the DCR of the PLB.  Sure enough, the
MCSR and PLB-DCR registers showed a DPLBError.

It's only a couple of asm statements:

mfspr   r30, 0x23c



Question to Xilinx experts:
What would cause the PLB to issue the DPLBError?????




<note to Xilinx>

Hey Xilinx guys!
Can you hack the gdb included with EDK such that it will recognize the
MCSR when gdb reads registers!

</note to Xilinx>

 


On Thu, 2008-02-21 at 11:04 -0700, David Baird wrote:
> Hi Robert,
> 
> On Wed, Feb 20, 2008 at 2:24 PM, Robert Woodworth
> <rwoodworth@securics.com> wrote:
> >  I'm under the suspicion that the PLB is issuing an error when switching
> >  to virtual mode and that there is either a timing/synthesis error or a
> >  fundamental error with the way the FPGA is getting synthesized with the
> >  PLB.
> 
> Can you offer a suggestion how I can check to see if the PLB is
> issuing an error (a good application note for me to read or anything)?
>  I was having a similar problem in virtual mode on one of my systems,
> and I might be able to see also if I am having a problem with the PLB
> bus.
> 
> -David

^ permalink raw reply

* [PATCH] [POWERPC] add target for building .dtb files
From: Grant Likely @ 2008-02-21 19:19 UTC (permalink / raw)
  To: linuxppc-dev, jwboyer

From: Grant Likely <grant.likely@secretlab.ca>

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

---

Josh, is this what your were looking for?

Cheers,
g.
---

 arch/powerpc/Makefile      |    2 +-
 arch/powerpc/boot/Makefile |    4 ++++
 2 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index ab5cfe8..dd80825 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -164,7 +164,7 @@ boot := arch/$(ARCH)/boot
 $(BOOT_TARGETS): vmlinux
 	$(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
 
-bootwrapper_install:
+bootwrapper_install %.dtb:
 	$(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
 
 define archhelp
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index d57a67d..fb29f10 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -311,6 +311,10 @@ $(obj)/treeImage.initrd.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
 $(obj)/treeImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
 	$(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts)
 
+# Rule to build device tree blobs
+$(obj)/%.dtb: $(dtstree)/%.dts $(obj)/dtc
+	$(obj)/dtc -O dtb -o $(obj)/$*.dtb -b 0 $(dtstree)/$*.dts
+
 # If there isn't a platform selected then just strip the vmlinux.
 ifeq (,$(image-y))
 image-y := vmlinux.strip

^ permalink raw reply related

* [PATCH] [POWERPC] 8xx: timebase frequency should not depend on bus-frequency
From: Anton Vorontsov @ 2008-02-21 19:45 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood

m8xx_setup.c says:
   /* Force all 8xx processors to use divide by 16 processor clock. */

And at the same time it is using bus-frequency for calculating
timebase. It is okay for most setups because bus-frequency is
equal to clock-frequency.

The problem emerges when cpu frequency is > 66MHz, quoting
u-boot/cpu/mpc8xx/speed.c:

        if (gd->cpu_clk <= 66000000) {
                sccr_reg |= SCCR_EBDF00;        /* bus division factor = 1 */
                gd->bus_clk = gd->cpu_clk;
        } else {
                sccr_reg |= SCCR_EBDF01;        /* bus division factor = 2 */
                gd->bus_clk = gd->cpu_clk / 2;
        }

So in case of cpu clock > 66MHz, bus_clk = cpu_clk / 2. An then, from
Linux, we calculate timebase frequency as tb_freq = bus_clk / 16,
that is cpu_clk / 2 / 16, which is wrong.

This patch fixes system time drifting problem on the EP885C board
running at 133MHz.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 arch/powerpc/platforms/8xx/m8xx_setup.c |    7 +------
 1 files changed, 1 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 184f998..0d9f75c 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -111,17 +111,12 @@ void __init mpc8xx_calibrate_decr(void)
 
 	/* Processor frequency is MHz.
 	 */
-	ppc_tb_freq = 50000000;
-	if (!get_freq("bus-frequency", &ppc_tb_freq)) {
-		printk(KERN_ERR "WARNING: Estimating decrementer frequency "
-		                "(not found)\n");
-	}
-	ppc_tb_freq /= 16;
 	ppc_proc_freq = 50000000;
 	if (!get_freq("clock-frequency", &ppc_proc_freq))
 		printk(KERN_ERR "WARNING: Estimating processor frequency "
 		                "(not found)\n");
 
+	ppc_tb_freq = ppc_proc_freq / 16;
 	printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq);
 
 	/* Perform some more timer/timebase initialization.  This used
-- 
1.5.2.2

^ permalink raw reply related

* Re: [PATCH] [POWERPC] 8xx: timebase frequency should not depend on bus-frequency
From: Scott Wood @ 2008-02-21 19:48 UTC (permalink / raw)
  To: Anton Vorontsov; +Cc: linuxppc-dev
In-Reply-To: <20080221194508.GA12896@localhost.localdomain>

Anton Vorontsov wrote:
> diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
> index 184f998..0d9f75c 100644
> --- a/arch/powerpc/platforms/8xx/m8xx_setup.c
> +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
> @@ -111,17 +111,12 @@ void __init mpc8xx_calibrate_decr(void)
>  
>  	/* Processor frequency is MHz.
>  	 */
> -	ppc_tb_freq = 50000000;
> -	if (!get_freq("bus-frequency", &ppc_tb_freq)) {
> -		printk(KERN_ERR "WARNING: Estimating decrementer frequency "
> -		                "(not found)\n");
> -	}
> -	ppc_tb_freq /= 16;
>  	ppc_proc_freq = 50000000;
>  	if (!get_freq("clock-frequency", &ppc_proc_freq))
>  		printk(KERN_ERR "WARNING: Estimating processor frequency "
>  		                "(not found)\n");
>  
> +	ppc_tb_freq = ppc_proc_freq / 16;

Shouldn't we just use the timebase-frequency property?

-Scott

^ permalink raw reply

* [PATCH] [USB POWERPC] ehci: fix ppc build
From: Anton Vorontsov @ 2008-02-21 19:49 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dbrownell, linux-usb

Currently, this setup:
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_HCD_PPC_OF=y

Will fail to build:
  CC      drivers/usb/host/ehci-hcd.o
drivers/usb/host/ehci-hcd.c:1018:2: error: #error "missing bus glue for ehci-hcd"
make[3]: *** [drivers/usb/host/ehci-hcd.o] Error 1

ehci-hcd.c actually contains OF_PLATFORM_DRIVER glue, so error is bogus.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 drivers/usb/host/ehci-hcd.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 4caa6a8..3a19b1a 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1014,7 +1014,7 @@ MODULE_LICENSE ("GPL");
 #endif
 
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
-    !defined(PS3_SYSTEM_BUS_DRIVER)
+    !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
 #error "missing bus glue for ehci-hcd"
 #endif
 
-- 
1.5.2.2

^ permalink raw reply related

* [PATCH] [USB POWERPC] ehci-fsl: add PPC_MPC837x to default y
From: Anton Vorontsov @ 2008-02-21 19:50 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linux-usb

Without this patch it's impossible to select ehci-fsl on PPC_MPC837x.
Another option would be to convert USB_EHCI_FSL to verbose bool,
but I presume EHCI_FSL is purposely made silent.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 drivers/usb/host/Kconfig |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index d97b16b..33da056 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -72,7 +72,7 @@ config USB_EHCI_FSL
 	bool
 	depends on USB_EHCI_HCD
 	select USB_EHCI_ROOT_HUB_TT
-	default y if MPC834x || PPC_MPC831x
+	default y if MPC834x || PPC_MPC831x || PPC_MPC837x
 	---help---
 	  Variation of ARC USB block used in some Freescale chips.
 
-- 
1.5.2.2

^ permalink raw reply related

* Re: [PATCH] [USB POWERPC] ehci-fsl: add PPC_MPC837x to default y
From: Scott Wood @ 2008-02-21 19:55 UTC (permalink / raw)
  To: Anton Vorontsov; +Cc: linuxppc-dev, linux-usb
In-Reply-To: <20080221195021.GC12896@localhost.localdomain>

Anton Vorontsov wrote:
> Without this patch it's impossible to select ehci-fsl on PPC_MPC837x.
> Another option would be to convert USB_EHCI_FSL to verbose bool,
> but I presume EHCI_FSL is purposely made silent.

I think making it verbose bool would be better.

-Scott

^ permalink raw reply

* Re: [PATCH] [USB POWERPC] ehci-fsl: add PPC_MPC837x to default y
From: Kumar Gala @ 2008-02-21 19:58 UTC (permalink / raw)
  To: Anton Vorontsov; +Cc: linuxppc-dev, linux-usb
In-Reply-To: <20080221195021.GC12896@localhost.localdomain>


On Feb 21, 2008, at 1:50 PM, Anton Vorontsov wrote:

> Without this patch it's impossible to select ehci-fsl on PPC_MPC837x.
> Another option would be to convert USB_EHCI_FSL to verbose bool,
> but I presume EHCI_FSL is purposely made silent.
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
> drivers/usb/host/Kconfig |    2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
> index d97b16b..33da056 100644
> --- a/drivers/usb/host/Kconfig
> +++ b/drivers/usb/host/Kconfig
> @@ -72,7 +72,7 @@ config USB_EHCI_FSL
> 	bool
> 	depends on USB_EHCI_HCD
> 	select USB_EHCI_ROOT_HUB_TT
> -	default y if MPC834x || PPC_MPC831x
> +	default y if MPC834x || PPC_MPC831x || PPC_MPC837x

Can we just change this to FSL_SOC

- k

^ permalink raw reply

* Re: [PATCH] [POWERPC] 8xx: timebase frequency should not depend on bus-frequency
From: Anton Vorontsov @ 2008-02-21 19:59 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <47BDD587.9060206@freescale.com>

On Thu, Feb 21, 2008 at 01:48:23PM -0600, Scott Wood wrote:
> Anton Vorontsov wrote:
> >diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c 
> >b/arch/powerpc/platforms/8xx/m8xx_setup.c
> >index 184f998..0d9f75c 100644
> >--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
> >+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
> >@@ -111,17 +111,12 @@ void __init mpc8xx_calibrate_decr(void)
> > 
> > 	/* Processor frequency is MHz.
> > 	 */
> >-	ppc_tb_freq = 50000000;
> >-	if (!get_freq("bus-frequency", &ppc_tb_freq)) {
> >-		printk(KERN_ERR "WARNING: Estimating decrementer frequency "
> >-		                "(not found)\n");
> >-	}
> >-	ppc_tb_freq /= 16;
> > 	ppc_proc_freq = 50000000;
> > 	if (!get_freq("clock-frequency", &ppc_proc_freq))
> > 		printk(KERN_ERR "WARNING: Estimating processor frequency "
> > 		                "(not found)\n");
> > 
> >+	ppc_tb_freq = ppc_proc_freq / 16;
> 
> Shouldn't we just use the timebase-frequency property?

Nope. Most u-boots currently do not setup timebase-frequency, and if
they are setting it up, they're doing it wrong, in sense that Linux
overwrites timebase setup (yeah, in this regard MPC8xx is special).

So, for MPC8xx, Linux doesn't care what timebase setup was used in
the firmware.

-- 
Anton Vorontsov
email: cbou@mail.ru
backup email: ya-cbou@yandex.ru
irc://irc.freenode.net/bd2

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox