/*
* Freescale MPC85xx/MPC86xx RapidIO RMU support
*
* Copyright 2009 Sysgo AG
* Thomas Moll <thomas.moll@sysgo.com>
* - fixed maintenance access routines, check for aligned access
*
* Copyright 2009 Integrated Device Technology, Inc.
* Alex Bounine <alexandre.bounine@idt.com>
* - Added Port-Write message handling
* - Added Machine Check exception handling
*
* Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc.
* Zhang Wei <wei.zhang@freescale.com>
* Lian Minghuan-B31939 <Minghuan.Lian@freescale.com>
* Liu Gang <Gang.Liu@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/types.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include "fsl_rio.h"
#define GET_RMM_HANDLE(mport) \
(((struct rio_priv *)(mport->priv))->rmm_handle)
/* RapidIO definition irq, which read from OF-tree */
#define IRQ_RIO_PW(m) (((struct fsl_rio_pw *)(m))->pwirq)
#define IRQ_RIO_BELL(m) (((struct fsl_rio_dbell *)(m))->bellirq)
#define IRQ_RIO_TX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->txirq)
#define IRQ_RIO_RX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->rxirq)
#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 RIO_IPWMR_SEN 0x00100000
#define RIO_IPWMR_QFIE 0x00000100
#define RIO_IPWMR_EIE 0x00000020
#define RIO_IPWMR_CQ 0x00000002
#define RIO_IPWMR_PWE 0x00000001
#define RIO_IPWSR_QF 0x00100000
#define RIO_IPWSR_TE 0x00000080
#define RIO_IPWSR_QFI 0x00000010
#define RIO_IPWSR_PWD 0x00000008
#define RIO_IPWSR_PWB 0x00000004
#define RIO_EPWISR 0x10010
/* EPWISR Error match value */
#define RIO_EPWISR_PINT1 0x80000000
#define RIO_EPWISR_PINT2 0x40000000
#define RIO_EPWISR_MU 0x00000002
#define RIO_EPWISR_PW 0x00000001
#define IPWSR_CLEAR 0x98
#define OMSR_CLEAR 0x1cb3
#define IMSR_CLEAR 0x491
#define IDSR_CLEAR 0x91
#define ODSR_CLEAR 0x1c00
#define LTLEECSR_ENABLE_ALL 0xFFC000FC
#define RIO_LTLEECSR 0x060c
#define RIO_IM0SR 0x64
#define RIO_IM1SR 0x164
#define RIO_OM0SR 0x4
#define RIO_OM1SR 0x104
#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 DOORBELL_DMR_DI 0x00000002
#define DOORBELL_DSR_TE 0x00000080
#define DOORBELL_DSR_QFI 0x00000010
#define DOORBELL_DSR_DIQI 0x00000001
#define DOORBELL_MESSAGE_SIZE 0x08
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;
};
struct rio_dbell_regs {
u32 odmr;
u32 odsr;
u32 pad1[4];
u32 oddpr;
u32 oddatr;
u32 pad2[3];
u32 odretcr;
u32 pad3[12];
u32 dmr;
u32 dsr;
u32 pad4;
u32 dqdpar;
u32 pad5;
u32 dqepar;
};
struct rio_pw_regs {
u32 pwmr;
u32 pwsr;
u32 epwqbar;
u32 pwqbar;
};
struct rio_tx_desc {
u32 pad1;
u32 saddr;
u32 dport;
u32 dattr;
u32 pad2;
u32 pad3;
u32 dwcnt;
u32 pad4;
};
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 fsl_rmu {
struct rio_msg_regs __iomem *msg_regs;
struct rio_msg_tx_ring msg_tx_ring;
struct rio_msg_rx_ring msg_rx_ring;
int txirq;
int rxirq;
};
struct rio_dbell_msg {
u16 pad1;
u16 tid;
u16 sid;
u16 info;
};
/**
* fsl_rio_tx_handler - MPC85xx outbound message interrupt handler
* @irq: Linux interrupt number
* @dev_instance: Pointer to interrupt-specific data
*
* Handles outbound message interrupts. Executes a register outbound
* mailbox event handler and acks the interrupt occurrence.
*/
static irqreturn_t
fsl_rio_tx_handler(int irq, void *dev_instance)
{
int osr;
struct rio_mport *port = (struct rio_mport *)dev_instance;
struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
osr = in_be32(&rmu->msg_regs->osr);
if (osr & RIO_MSG_OSR_TE) {
pr_info("RIO: outbound message transmission error\n");
out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_TE);
goto out;
}
if (osr & RIO_MSG_OSR_QOI)