/* * SBE 2T3E3 synchronous serial card driver for Linux * * Copyright (C) 2009-2010 Krzysztof Halasa * * 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 #include #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); }