summaryrefslogtreecommitdiffstats
path: root/drivers/staging/sbe-2t3e3/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/sbe-2t3e3/io.c')
-rw-r--r--drivers/staging/sbe-2t3e3/io.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/drivers/staging/sbe-2t3e3/io.c b/drivers/staging/sbe-2t3e3/io.c
new file mode 100644
index 0000000..b458ff0
--- /dev/null
+++ b/drivers/staging/sbe-2t3e3/io.c
@@ -0,0 +1,352 @@
+/*
+ * SBE 2T3E3 synchronous serial card driver for Linux
+ *
+ * Copyright (C) 2009-2010 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This code is based on a driver written by SBE Inc.
+ */
+
+#include <linux/ip.h>
+#include <asm/system.h>
+#include "2t3e3.h"
+#include "ctrl.h"
+
+/* All access to registers done via the 21143 on port 0 must be
+ * protected via the card->bootrom_lock. */
+
+/* priviate define to be used here only - must be protected by card->bootrom_lock */
+#define cpld_write_nolock(channel, reg, val) \
+ bootrom_write((channel), CPLD_MAP_REG(reg, channel), val)
+
+u32 cpld_read(struct channel *channel, u32 reg)
+{
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&channel->card->bootrom_lock, flags);
+ val = bootrom_read((channel), CPLD_MAP_REG(reg, channel));
+ spin_unlock_irqrestore(&channel->card->bootrom_lock, flags);
+ return val;
+}
+
+/****************************************
+ * Access via BootROM port
+ ****************************************/
+
+u32 bootrom_read(struct channel *channel, u32 reg)
+{
+ unsigned long addr = channel->card->bootrom_addr;
+ u32 result;
+
+ /* select BootROM address */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_PROGRAMMING_ADDRESS, reg & 0x3FFFF);
+
+ /* select reading from BootROM */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_READ_OPERATION |
+ SBE_2T3E3_21143_VAL_BOOT_ROM_SELECT);
+
+ udelay(2); /* 20 PCI cycles */
+
+ /* read from BootROM */
+ result = dc_read(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT) & 0xff;
+
+ /* reset CSR9 */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0);
+
+ return result;
+}
+
+void bootrom_write(struct channel *channel, u32 reg, u32 val)
+{
+ unsigned long addr = channel->card->bootrom_addr;
+
+ /* select BootROM address */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_PROGRAMMING_ADDRESS, reg & 0x3FFFF);
+
+ /* select writting to BootROM */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_WRITE_OPERATION |
+ SBE_2T3E3_21143_VAL_BOOT_ROM_SELECT |
+ (val & 0xff));
+
+ udelay(2); /* 20 PCI cycles */
+
+ /* reset CSR9 */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0);
+}
+
+
+/****************************************
+ * Access via Serial I/O port
+ ****************************************/
+
+static u32 serialrom_read_bit(struct channel *channel)
+{
+ unsigned long addr = channel->card->bootrom_addr;
+ u32 bit;
+
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_READ_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CLOCK |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock high */
+
+ bit = (dc_read(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT) &
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_DATA_OUT) > 0 ? 1 : 0;
+
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_READ_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */
+
+ return bit;
+}
+
+static void serialrom_write_bit(struct channel *channel, u32 bit)
+{
+ unsigned long addr = channel->card->bootrom_addr;
+ u32 lastbit = -1;
+
+ bit &= 1;
+
+ if (bit != lastbit) {
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_WRITE_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT |
+ (bit << 2)); /* clock low */
+
+ lastbit = bit;
+ }
+
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_WRITE_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CLOCK |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT |
+ (bit << 2)); /* clock high */
+
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_WRITE_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT |
+ (bit << 2)); /* clock low */
+}
+
+/****************************************
+ * Access to SerialROM (eeprom)
+ ****************************************/
+
+u32 t3e3_eeprom_read_word(struct channel *channel, u32 address)
+{
+ unsigned long addr = channel->card->bootrom_addr;
+ u32 i, val;
+ unsigned long flags;
+
+ address &= 0x3f;
+
+ spin_lock_irqsave(&channel->card->bootrom_lock, flags);
+
+ /* select correct Serial Chip */
+ cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT,
+ SBE_2T3E3_CPLD_VAL_EEPROM_SELECT);
+
+ /* select reading from Serial I/O Bus */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_READ_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */
+
+ /* select read operation */
+ serialrom_write_bit(channel, 0);
+ serialrom_write_bit(channel, 1);
+ serialrom_write_bit(channel, 1);
+ serialrom_write_bit(channel, 0);
+
+ for (i = 0x20; i; i >>= 1)
+ serialrom_write_bit(channel, address & i ? 1 : 0);
+
+ val = 0;
+ for (i = 0x8000; i; i >>= 1)
+ val |= (serialrom_read_bit(channel) ? i : 0);
+
+ /* Reset 21143's CSR9 */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_READ_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0);
+
+ /* Unselect Serial Chip */
+ cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, 0);
+
+ spin_unlock_irqrestore(&channel->card->bootrom_lock, flags);
+
+ return ntohs(val);
+}
+
+
+/****************************************
+ * Access to Framer
+ ****************************************/
+
+u32 exar7250_read(struct channel *channel, u32 reg)
+{
+ u32 result;
+ unsigned long flags;
+
+#if 0
+ switch (reg) {
+ case SBE_2T3E3_FRAMER_REG_OPERATING_MODE:
+ return channel->framer_regs[reg];
+ break;
+ default:
+ }
+#endif
+
+ spin_lock_irqsave(&channel->card->bootrom_lock, flags);
+
+ result = bootrom_read(channel, cpld_reg_map[SBE_2T3E3_CPLD_REG_FRAMER_BASE_ADDRESS]
+ [channel->h.slot] + (t3e3_framer_reg_map[reg] << 2));
+
+ spin_unlock_irqrestore(&channel->card->bootrom_lock, flags);
+
+ return result;
+}
+
+void exar7250_write(struct channel *channel, u32 reg, u32 val)
+{
+ unsigned long flags;
+
+ val &= 0xff;
+ channel->framer_regs[reg] = val;
+
+ spin_lock_irqsave(&channel->card->bootrom_lock, flags);
+
+ bootrom_write(channel, cpld_reg_map[SBE_2T3E3_CPLD_REG_FRAMER_BASE_ADDRESS]
+ [channel->h.slot] + (t3e3_framer_reg_map[reg] << 2), val);
+
+ spin_unlock_irqrestore(&channel->card->bootrom_lock, flags);
+}
+
+
+/****************************************
+ * Access to LIU
+ ****************************************/
+
+u32 exar7300_read(struct channel *channel, u32 reg)
+{
+ unsigned long addr = channel->card->bootrom_addr, flags;
+ u32 i, val;
+
+#if 0
+ switch (reg) {
+ case SBE_2T3E3_LIU_REG_REG1:
+ case SBE_2T3E3_LIU_REG_REG2:
+ case SBE_2T3E3_LIU_REG_REG3:
+ case SBE_2T3E3_LIU_REG_REG4:
+ return channel->liu_regs[reg];
+ break;
+ default:
+ }
+#endif
+
+ /* select correct Serial Chip */
+
+ spin_lock_irqsave(&channel->card->bootrom_lock, flags);
+
+ cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT,
+ cpld_val_map[SBE_2T3E3_CPLD_VAL_LIU_SELECT][channel->h.slot]);
+
+ /* select reading from Serial I/O Bus */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_READ_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */
+
+ /* select read operation */
+ serialrom_write_bit(channel, 1);
+
+ /* Exar7300 register address is 4 bit long */
+ reg = t3e3_liu_reg_map[reg];
+ for (i = 0; i < 4; i++, reg >>= 1) /* 4 bits of SerialROM address */
+ serialrom_write_bit(channel, reg & 1);
+ for (i = 0; i < 3; i++) /* remaining 3 bits of SerialROM address */
+ serialrom_write_bit(channel, 0);
+
+ val = 0; /* Exar7300 register value is 5 bit long */
+ for (i = 0; i < 8; i++) /* 8 bits of SerialROM value */
+ val += (serialrom_read_bit(channel) << i);
+
+ /* Reset 21143's CSR9 */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_READ_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0);
+
+ /* Unselect Serial Chip */
+ cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, 0);
+
+ spin_unlock_irqrestore(&channel->card->bootrom_lock, flags);
+
+ return val;
+}
+
+void exar7300_write(struct channel *channel, u32 reg, u32 val)
+{
+ unsigned long addr = channel->card->bootrom_addr, flags;
+ u32 i;
+
+ channel->liu_regs[reg] = val;
+
+ /* select correct Serial Chip */
+
+ spin_lock_irqsave(&channel->card->bootrom_lock, flags);
+
+ cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT,
+ cpld_val_map[SBE_2T3E3_CPLD_VAL_LIU_SELECT][channel->h.slot]);
+
+ /* select writting to Serial I/O Bus */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_WRITE_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */
+
+ /* select write operation */
+ serialrom_write_bit(channel, 0);
+
+ /* Exar7300 register address is 4 bit long */
+ reg = t3e3_liu_reg_map[reg];
+ for (i = 0; i < 4; i++) { /* 4 bits */
+ serialrom_write_bit(channel, reg & 1);
+ reg >>= 1;
+ }
+ for (i = 0; i < 3; i++) /* remaining 3 bits of SerialROM address */
+ serialrom_write_bit(channel, 0);
+
+ /* Exar7300 register value is 5 bit long */
+ for (i = 0; i < 5; i++) {
+ serialrom_write_bit(channel, val & 1);
+ val >>= 1;
+ }
+ for (i = 0; i < 3; i++) /* remaining 3 bits of SerialROM value */
+ serialrom_write_bit(channel, 0);
+
+ /* Reset 21143_CSR9 */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT,
+ SBE_2T3E3_21143_VAL_WRITE_OPERATION |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT |
+ SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */
+ dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0);
+
+ /* Unselect Serial Chip */
+ cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, 0);
+
+ spin_unlock_irqrestore(&channel->card->bootrom_lock, flags);
+}
OpenPOWER on IntegriCloud