/*-
 * TODO:
 * [1] integrate into current if_ed.c
 * [2] parse tuples to find out where to map the shared memory buffer,
 *     and what to write into the configuration register
 * [3] move pcic-specific code into a separate module.
 *
 * Device driver for IBM PCMCIA Credit Card Adapter for Ethernet,
 * if_ze.c
 *
 * Based on the Device driver for National Semiconductor DS8390 ethernet
 * adapters by David Greenman.  Modifications for PCMCIA by Keith Moore.
 * Adapted for FreeBSD 1.1.5 by Jordan Hubbard.
 *
 * Currently supports only the IBM Credit Card Adapter for Ethernet, but
 * could probably work with other PCMCIA cards also, if it were modified
 * to get the locations of the PCMCIA configuration option register (COR)
 * by parsing the configuration tuples, rather than by hard-coding in
 * the value expected by IBM's card.
 *
 * Sources for data on the PCMCIA/IBM CCAE specific portions of the driver:
 *
 * [1] _Local Area Network Credit Card Adapters Technical Reference_,
 *     IBM Corp., SC30-3585-00, part # 33G9243.
 * [2] "pre-alpha" PCMCIA support code for Linux by Barry Jaspan.
 * [3] Intel 82536SL PC Card Interface Controller Data Sheet, Intel
 *     Order Number 290423-002
 * [4] National Semiconductor DP83902A ST-NIC (tm) Serial Network
 *     Interface Controller for Twisted Pair data sheet.
 *
 *
 * Copyright (C) 1993, David Greenman. This software may be used, modified,
 *   copied, distributed, and sold, in both source and binary form provided
 *   that the above copyright and these terms are retained. Under no
 *   circumstances is the author responsible for the proper functioning
 *   of this software, nor does the author assume any responsibility
 *   for damages incurred with its use.
 */

#ifndef __PCIC_H__
#define __PCIC_H__

/*****************************************************************************
 *                 pcmcia controller chip (PCIC) support                     *
 *               (eventually, move this to a separate file)                  *
 *****************************************************************************/
#include "ic/i82365.h"

/*
 * Each PCIC chip (82365SL or clone) can handle two card slots, and there
 * can be up to four PCICs in a system.  (On some machines, not all of the
 * address lines are decoded, so a card may appear to be in more than one
 * slot.)
 */
#define MAXSLOT 8

/*
 * To access a register on the PCIC for a particular slot, you
 * first write the correct OFFSET value for that slot in the
 * INDEX register for the PCIC controller.  You then read or write
 * the value from or to the DATA register for that controller.
 *
 * The first pair of chips shares I/O addresss for DATA and INDEX,
 * as does the second pair.   (To the programmer, it looks like each
 * pair is a single chip.)  The i/o port addresses are hard-wired
 * into the PCIC; so the following addresses should be valid for
 * any machine that uses this chip.
 */

#define PCIC_INDEX_0	0x3E0	/* index reg, chips 0 and 1 */
#define PCIC_DATA_0	0x3E1	/* data register, chips 0 and 1 */
#define PCIC_INDEX_1	0x3E2	/* index reg, chips 1 and 2 */
#define PCIC_DATA_1	0x3E3	/* data register, chips 1 and 2 */

/*
 * Given a slot number, calculate the INDEX and DATA registers
 * to talk to that slot.  OFFSET is added to the register number
 * to address the registers for a particular slot.
 */
#define INDEX(slot) ((slot) < 4 ? PCIC_INDEX_0 : PCIC_INDEX_1)
#define DATA(slot) ((slot) < 4 ? PCIC_DATA_0 : PCIC_DATA_1)
#define OFFSET(slot) ((slot) % 4 * 0x40)

/*
 * There are 5 sets (windows) of memory mapping registers on the PCIC chip
 * for each slot, numbered 0..4.
 *
 * They start at 10/50 hex within the chip's register space (not system
 * I/O space), and are eight addresses apart.  These are actually pairs of
 * 8-bit-wide registers (low byte first, then high byte) since the
 * address fields are actually 12 bits long.  The upper bits are used
 * for other things like 8/16-bit select and wait states.
 *
 * Memory mapping registers include start/stop addresses to define the
 * region to be mapped (in terms of system memory addresses), and
 * an offset register to allow for translation from system space
 * to card space.  The lower 12 bits aren't included in these, so memory is
 * mapped in 4K chunks.
 */
#define MEM_START_ADDR(window) (((window) * 0x08) + 0x10)
#define MEM_STOP_ADDR(window) (((window) * 0x08) + 0x12)
#define MEM_OFFSET(window) (((window) * 0x08) + 0x14)
/*
 * this bit gets set in the address window enable register (PCIC_ADDRWINE)
 * to enable a particular address window.
 */
#define MEM_ENABLE_BIT(window) ((1) << (window))

/*
 * There are two i/o port addressing windows.  I/O ports cannot be
 * relocated within system i/o space (unless the card doesn't decode
 * all of the address bits); unlike card memory, there is no address
 * translation offset.
 */
#define IO_START_ADDR(window) ((window) ? PCIC_IO1_STL : PCIC_IO0_STL)
#define IO_STOP_ADDR(window) ((window) ? PCIC_IO1_SPL : PCIC_IO0_SPL)
#define IO_ENABLE_BIT(window) ((window) ? PCIC_IO1_EN : PCIC_IO0_EN)
#define IO_CS16_BIT(window) ((window) ? PCIC_IO1_CS16 : PCIC_IO0_CS16)

/*
 * types of mapped memory
 */
enum memtype { COMMON, ATTRIBUTE };

/*
 * read a byte from a pcic register for a particular slot
 */
static inline unsigned char
pcic_getb (int slot, int reg)
{
    outb (INDEX(slot), OFFSET (slot) + reg);
    return inb (DATA (slot));
}

/*
 * write a byte to a pcic register for a particular slot
 */
static inline void
pcic_putb (int slot, int reg, unsigned char val)
{
    outb (INDEX(slot), OFFSET (slot) + reg);
    outb (DATA (slot), val);
}

/*
 * read a word from a pcic register for a particular slot
 */
static inline unsigned short
pcic_getw (int slot, int reg)
{
    return pcic_getb (slot, reg) | (pcic_getb (slot, reg+1) << 8);
}

/*
 * write a word to a pcic register at a particular slot
 */
static inline void
pcic_putw (int slot, int reg, unsigned short val)
{
    pcic_putb (slot, reg, val & 0xff);
    pcic_putb (slot, reg + 1, (val >> 8) & 0xff);
}


void pcic_print_regs (int slot);
void pcic_map_memory (int slot, int window, unsigned long sys_addr,
                      unsigned long card_addr, unsigned long length,
                      enum memtype type, int width);
void pcic_unmap_memory (int slot, int window);
void pcic_map_io (int slot, int window, unsigned short base,
                  unsigned short length, unsigned short width);
#ifdef TEST
void pcic_unmap_io (int slot, int window);
#endif /* TEST */
void pcic_map_irq (int slot, int irq);
void pcic_power_on (int slot);
void pcic_power_off (int slot);
void pcic_reset (int slot);


#endif /* __PCIC_H__ */
