/*
* Freescale MPC85xx/MPC86xx RapidIO support
*
* Copyright (C) 2007, 2008 Freescale Semiconductor, Inc.
* Zhang Wei <wei.zhang@freescale.com>
*
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
* 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.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/rio.h>
#include <linux/rio_drv.h>
#include <linux/of_platform.h>
#include <asm/io.h>
/* RapidIO definition irq, which read from OF-tree */
#define IRQ_RIO_BELL(m) (((struct rio_priv *)(m->priv))->bellirq)
#define IRQ_RIO_TX(m) (((struct rio_priv *)(m->priv))->txirq)
#define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq)
#define RIO_ATMU_REGS_OFFSET 0x10c00
#define RIO_MSG_REGS_OFFSET 0x11000
#define RIO_MAINT_WIN_SIZE 0x400000
#define RIO_DBELL_WIN_SIZE 0x1000
#define RIO_MSG_OMR_MUI 0x00000002
#define RIO_MSG_OSR_TE 0x00000080
#define RIO_MSG_OSR_QOI 0x00000020
#define RIO_MSG_OSR_QFI 0x00000010
#define RIO_MSG_OSR_MUB 0x00000004
#define RIO_MSG_OSR_EOMI 0x00000002
#define RIO_MSG_OSR_QEI 0x00000001
#define RIO_MSG_IMR_MI 0x00000002
#define RIO_MSG_ISR_TE 0x00000080
#define RIO_MSG_ISR_QFI 0x00000010
#define RIO_MSG_ISR_DIQI 0x00000001
#define RIO_MSG_DESC_SIZE 32
#define RIO_MSG_BUFFER_SIZE 4096
#define RIO_MIN_TX_RING_SIZE 2
#define RIO_MAX_TX_RING_SIZE 2048
#define RIO_MIN_RX_RING_SIZE 2
#define RIO_MAX_RX_RING_SIZE 2048
#define DOORBELL_DMR_DI 0x00000002
#define DOORBELL_DSR_TE 0x00000080
#define DOORBELL_DSR_QFI 0x00000010
#define DOORBELL_DSR_DIQI 0x00000001
#define DOORBELL_TID_OFFSET 0x03
#define DOORBELL_SID_OFFSET 0x05
#define DOORBELL_INFO_OFFSET 0x06
#define DOORBELL_MESSAGE_SIZE 0x08
#define DBELL_SID(x) (*(u8 *)(x + DOORBELL_SID_OFFSET))
#define DBELL_TID(x) (*(u8 *)(x + DOORBELL_TID_OFFSET))
#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET))
struct rio_atmu_regs {
u32 rowtar;
u32 pad1;
u32 rowbar;
u32 pad2;
u32 rowar;
u32 pad3[3];
};
struct rio_msg_regs {
u32 omr;
u32 osr;
u32 pad1;
u32 odqdpar;
u32 pad2;
u32 osar;
u32 odpr;
u32 odatr;
u32 odcr;
u32 pad3;
u32 odqepar;
u32 pad4[13];
u32 imr;
u32 isr;
u32 pad5;
u32 ifqdpar;
u32 pad6;
u32 ifqepar;
u32 pad7[250];
u32 dmr;
u32 dsr;
u32 pad8;
u32 dqdpar;
u32 pad9;
u32 dqepar;
u32 pad10[26];
u32 pwmr;
u32 pwsr;
u32 pad11;
u32 pwqbar;
};
struct rio_tx_desc {
u32 res1;
u32 saddr;
u32 dport;
u32 dattr;
u32 res2;
u32 res3;
u32 dwcnt;
u32 res4;
};
struct rio_dbell_ring {
void *virt;
dma_addr_t phys;
};
struct rio_msg_tx_ring {
void *virt;
dma_addr_t phys;
void *virt_buffer[RIO_MAX_TX_RING_SIZE];
dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
int tx_slot;
int size;
void *dev_id;
};
struct rio_msg_rx_ring {
void *virt;
dma_addr_t phys;
void *virt_buffer[RIO_MAX_RX_RING_SIZE];
int rx_slot;
int size;
void *dev_id;
};
struct rio_priv {
void __iomem *regs_win;
struct rio_atmu_regs __iomem *atmu_regs;
struct rio_atmu_regs __iomem *maint_atmu_regs;
struct rio_atmu_regs __iomem *dbell_atmu_regs;
void __iomem *dbell_win;
void __iomem *maint_win;
struct rio_msg_regs __iomem *msg_regs;
struct rio_dbell_ring dbell_ring;
struct rio_msg_tx_ring msg_tx_ring;
struct rio_msg_rx_ring msg_rx_ring;
int bellirq;
int txirq;
int rxirq;
};
/**
* fsl_rio_doorbell_send - Send a MPC85xx doorbell message
* @index: ID of RapidIO interface
* @destid: Destination ID of target device
* @data: 16-bit info field of RapidIO doorbell message
*
* Sends a MPC85xx doorbell message. Returns %0 on success or
* %-EINVAL on failure.
*/
static int fsl_rio_doorbell_send(struct rio_mport *mport,
int index, u16 destid, u16 data)
{
struct rio_priv *priv = mport->priv;
pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
index, destid, data);
out_be32(&priv->dbell_atmu_regs->rowtar, destid << 22);
out_be16(priv->dbell_win, data);
return 0;
}
/**
* fsl_local_config_read - Generate a MPC85xx local config space read
* @index: ID of RapdiIO interface
* @offset: Offset into configuration space
* @len: Length (in bytes) of the maintenance transaction
* @data: Value to be read into
*
* Generates a MPC85xx local configuration space read. Returns %0 on
* success or %-EINVAL on failure.
*/
static int fsl_local_config_read(struct rio_mport *mport,
int index, u32 offset, int len, u32