On Sun, Apr 27, 2008 at 12:59 AM, Peter Korsgaard <[EMAIL PROTECTED]> wrote: > 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 <[EMAIL PROTECTED]> > Acked-by: David Brownell <[EMAIL PROTECTED]> Acked-by: Grant Likely <[EMAIL PROTECTED]>
> --- > 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/byteorder.h> > +#include <linux/io.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 > -- Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev