/*
* Copyright(c) 2007 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Maintained at www.Open-FCoE.org
*/
#ifndef _FC_FRAME_H_
#define _FC_FRAME_H_
#include <linux/scatterlist.h>
#include <linux/skbuff.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/fc/fc_fs.h>
#include <scsi/fc/fc_fcp.h>
#include <scsi/fc/fc_encaps.h>
#include <linux/if_ether.h>
/* some helpful macros */
#define ntohll(x) be64_to_cpu(x)
#define htonll(x) cpu_to_be64(x)
static inline u32 ntoh24(const u8 *p)
{
return (p[0] << 16) | (p[1] << 8) | p[2];
}
static inline void hton24(u8 *p, u32 v)
{
p[0] = (v >> 16) & 0xff;
p[1] = (v >> 8) & 0xff;
p[2] = v & 0xff;
}
/*
* The fc_frame interface is used to pass frame data between functions.
* The frame includes the data buffer, length, and SOF / EOF delimiter types.
* A pointer to the port structure of the receiving port is also includeded.
*/
#define FC_FRAME_HEADROOM 32 /* headroom for VLAN + FCoE headers */
#define FC_FRAME_TAILROOM 8 /* trailer space for FCoE */
/* Max number of skb frags allowed, reserving one for fcoe_crc_eof page */
#define FC_FRAME_SG_LEN (MAX_SKB_FRAGS - 1)
#define fp_skb(fp) (&((fp)->skb))
#define fr_hdr(fp) ((fp)->skb.data)
#define fr_len(fp) ((fp)->skb.len)
#define fr_cb(fp) ((struct fcoe_rcv_info *)&((fp)->skb.cb[0]))
#define fr_dev(fp) (fr_cb(fp)->fr_dev)
#define fr_seq(fp) (fr_cb(fp)->fr_seq)
#define fr_sof(fp) (fr_cb(fp)->fr_sof)
#define fr_eof(fp) (fr_cb(fp)->fr_eof)
#define fr_flags(fp) (fr_cb(fp)->fr_flags)
#define fr_encaps(fp) (fr_cb(fp)->fr_encaps)
#define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload)
#define fr_fsp(fp) (fr_cb(fp)->fr_fsp)
#define fr_crc(fp) (fr_cb(fp)->fr_crc)
struct fc_frame {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long *//*
* SPI_PPC4XX SPI controller driver.
*
* Copyright (C) 2007 Gary Jennejohn <garyj@denx.de>
* Copyright 2008 Stefan Roese <sr@denx.de>, DENX Software Engineering
* Copyright 2009 Harris Corporation, Steven A. Falco <sfalco@harris.com>
*
* Based in part on drivers/spi/spi_s3c24xx.c
*
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
/*
* The PPC4xx SPI controller has no FIFO so each sent/received byte will
* generate an interrupt to the CPU. This can cause high CPU utilization.
* This driver allows platforms to reduce the interrupt load on the CPU
* during SPI transfers by setting max_speed_hz via the device tree.
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <asm/io.h>
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
/* bits in mode register - bit 0 is MSb */
/*
* SPI_PPC4XX_MODE_SCP = 0 means "data latched on trailing edge of clock"
* SPI_PPC4XX_MODE_SCP = 1 means "data latched on leading edge of clock"
* Note: This is the inverse of CPHA.
*/
#define SPI_PPC4XX_MODE_SCP (0x80 >> 3)
/* SPI_PPC4XX_MODE_SPE = 1 means "port enabled" */
#define SPI_PPC4XX_MODE_SPE (0x80 >> 4)
/*
* SPI_PPC4XX_MODE_RD = 0 means "MSB first" - this is the normal mode
* SPI_PPC4XX_MODE_RD = 1 means "LSB first" - this is bit-reversed mode
* Note: This is identical to SPI_LSB_FIRST.
*/
#define SPI_PPC4XX_MODE_RD (0x80 >> 5)
/*
* SPI_PPC4XX_MODE_CI = 0 means "clock idles low"
* SPI_PPC4XX_MODE_CI = 1 means "clock idles high"
* Note: This is identical to CPOL.
*/
#define SPI_PPC4XX_MODE_CI (0x80 >> 6)
/*
* SPI_PPC4XX_MODE_IL = 0 means "loopback disable"
* SPI_PPC4XX_MODE_IL = 1 means "loopback enable"
*/
#define SPI_PPC4XX_MODE_IL (0x80 >> 7)
/* bits in control register */
/* starts a transfer when set */
#define SPI_PPC4XX_CR_STR (0x80 >> 7)
/* bits in status register */
/* port is busy with a transfer */
#define SPI_PPC4XX_SR_BSY (0x80 >> 6)
/* RxD ready */
#define SPI_PPC4XX_SR_RBR (0x80 >> 7)
/* clock settings (SCP and CI) for various SPI modes */
#define SPI_CLK_MODE0 (SPI_PPC4XX_MODE_SCP | 0)
#define SPI_CLK_MODE1 (0 | 0)
#define SPI_CLK_MODE2 (SPI_PPC4XX_MODE_SCP | SPI_PPC4XX_MODE_CI)
#define SPI_CLK_MODE3 (0 | SPI_PPC4XX_MODE_CI)
#define DRIVER_NAME "spi_ppc4xx_of"
struct spi_ppc4xx_regs {
u8 mode;
u8 rxd;
u8 txd;
u8 cr;
u8 sr;
u8 dummy;
/*
* Clock divisor modulus register
* This uses the following formula:
* SCPClkOut = OPBCLK/(4(CDM + 1))
* or
* CDM = (OPBCLK/4*SCPClkOut) - 1
* bit 0 is the MSb!
*/
u8 cdm;
};
/* SPI Controller driver's private data. */
struct ppc4xx_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
struct completion done;
u64 mapbase;
u64 mapsize;
int irqnum;
/* need this to set the SPI clock */
unsigned int opb_freq;
/* for transfers */
int len;
int count;
/* data buffers */
const unsigned char *tx;
unsigned char *rx;
int *gpios;
struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */
struct spi_master *master;
struct device *dev;
};
/* need this so we can set the clock in the chipselect routine */
struct spi_ppc4xx_cs {
u8 mode;
};
static int spi_ppc4xx_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct ppc4xx_spi *hw;
u8 data;
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len);
hw = spi_master_get_devdata(spi->master);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->len = t->len;
hw->count = 0;
/* send the first byte */
data = hw->tx ? hw->tx[0] : 0;
out_8(&hw->regs->txd, data);
out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
wait_for_completion(&hw->done);
return hw->count;
}
static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t