/*
* PMC-Sierra MSP board specific pci_ops
*
* Copyright 2001 MontaVista Software Inc.
* Copyright 2005-2007 PMC-Sierra, Inc
*
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
* Much of the code is derived from the original DDB5074 port by
* Geert Uytterhoeven <geert@sonycom.com>
*
* 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.
*
*/
#define PCI_COUNTERS 1
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS)
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#endif /* CONFIG_PROC_FS && PCI_COUNTERS */
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/byteorder.h>
#if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL)
#include <asm/mipsmtregs.h>
#endif
#include <msp_prom.h>
#include <msp_cic_int.h>
#include <msp_pci.h>
#include <msp_regs.h>
#include <msp_regops.h>
#define PCI_ACCESS_READ 0
#define PCI_ACCESS_WRITE 1
#if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS)
static char proc_init;
extern struct proc_dir_entry *proc_bus_pci_dir;
unsigned int pci_int_count[32];
static void pci_proc_init(void);
/*****************************************************************************
*
* FUNCTION: read_msp_pci_counts
* _________________________________________________________________________
*
* DESCRIPTION: Prints the count of how many times each PCI
* interrupt has asserted. Can be invoked by the
* /proc filesystem.
*
* INPUTS: page - part of STDOUT calculation
* off - part of STDOUT calculation
* count - part of STDOUT calculation
* data - unused
*
* OUTPUTS: start - new start location
* eof - end of file pointer
*
* RETURNS: len - STDOUT length
*
****************************************************************************/
static int read_msp_pci_counts(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int i;
int len = 0;
unsigned int intcount, total = 0;
for (i = 0; i < 32; ++i) {
intcount = pci_int_count[i];
if (intcount != 0) {
len += sprintf(page + len, "[%d] = %u\n", i, intcount);
total += intcount;
}
}
len += sprintf(page + len, "total = %u\n", total);
if (len <= off+count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
}
/*****************************************************************************
*
* FUNCTION: gen_pci_cfg_wr
* _________________________________________________________________________
*
* DESCRIPTION: Generates a configuration write cycle for debug purposes.
* The IDSEL line asserted and location and data written are
* immaterial. Just want to be able to prove that a
* configuration write can be correctly generated on the
* PCI bus. Intent is that this function by invocable from
* the /proc filesystem.
*
* INPUTS: page - part of STDOUT calculation
* off - part of STDOUT calculation
* count - part of STDOUT calculation
* data - unused
*
* OUTPUTS: start - new start location
* eof - end of file pointer
*
* RETURNS: len - STDOUT length
*
****************************************************************************/
static int gen_pci_cfg_wr(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
unsigned char where = 0; /* Write to static Device/Vendor ID */
unsigned char bus_num = 0; /* Bus 0 */
unsigned char dev_fn = 0xF; /* Arbitrary device number */
u32 wr_data = 0xFF00AA00; /* Arbitrary data */
struct msp_pci_regs *preg = (void *)PCI_BASE_REG;
int len = 0;
unsigned long value;
int intr;
len += sprintf(page + len, "PMC MSP PCI: Beginning\n");
if (proc_init == 0) {
pci_proc_init();
proc_init = ~0;
}
len += sprintf(page + len, "PMC MSP PCI: Before Cfg Wr\n");
/*
* Generate PCI Configuration Write Cycle
*/
/* Clear cause register bits */
preg->if_status = ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F);
/* Setup address that is to appear on PCI bus */
preg->config_addr = BPCI_CFGADDR_ENABLE |
(bus_num << BPCI_CFGADDR_BUSNUM_SHF) |
(dev_fn << BPCI_CFGADDR_FUNCTNUM_SHF) |
(where & 0xFC);
value = cpu_to_le32(wr_data);
/* Launch the PCI configuration write cycle */
*PCI_CONFIG_SPACE_REG = value;
/*
* Check if the PCI configuration cycle (rd or wr) succeeded, by
* checking the status bits for errors like master or target abort.
*/
intr = preg->if_status;
len += sprintf(page + len, "PMC MSP PCI: After Cfg Wr\n");
/* Handle STDOUT calculations */
if (len <= off+count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
}