196 lines
4.4 KiB
C
196 lines
4.4 KiB
C
/*`
|
|
* mp1000-seprom.c
|
|
*
|
|
* This file contains the Serial EEPROM code for the MP1000 board
|
|
*
|
|
* Copyright (C) 2005 Comdial Corporation
|
|
*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <asm/hardware.h>
|
|
#include <asm/hardware/clps7111.h>
|
|
#include <asm/arch/mp1000-seprom.h>
|
|
|
|
/* If SepromInit() can initialize and checksum the seprom successfully, */
|
|
/* then it will point seprom_data_ptr at the shadow copy. */
|
|
|
|
static eeprom_struct seprom_data; /* shadow copy of seprom content */
|
|
|
|
eeprom_struct *seprom_data_ptr = 0; /* 0 => not initialized */
|
|
|
|
/*
|
|
* Port D Bit 5 is Chip Select for EEPROM
|
|
* Port E Bit 0 is Input, Data out from EEPROM
|
|
* Port E Bit 1 is Output, Data in to EEPROM
|
|
* Port E Bit 2 is Output, CLK to EEPROM
|
|
*/
|
|
|
|
static char *port_d_ptr = (char *)(CLPS7111_VIRT_BASE + PDDR);
|
|
static char *port_e_ptr = (char *)(CLPS7111_VIRT_BASE + PEDR);
|
|
|
|
#define NO_OF_SHORTS 64 // Device is 64 x 16 bits
|
|
#define ENABLE_RW 0
|
|
#define DISABLE_RW 1
|
|
|
|
static inline void toggle_seprom_clock(void)
|
|
{
|
|
*port_e_ptr |= HwPortESepromCLK;
|
|
*port_e_ptr &= ~(HwPortESepromCLK);
|
|
}
|
|
|
|
static inline void select_eeprom(void)
|
|
{
|
|
*port_d_ptr |= HwPortDEECS;
|
|
*port_e_ptr &= ~(HwPortESepromCLK);
|
|
}
|
|
|
|
static inline void deselect_eeprom(void)
|
|
{
|
|
*port_d_ptr &= ~(HwPortDEECS);
|
|
*port_e_ptr &= ~(HwPortESepromDIn);
|
|
}
|
|
|
|
/*
|
|
* GetSepromDataPtr - returns pointer to shadow (RAM) copy of seprom
|
|
* and returns 0 if seprom is not initialized or
|
|
* has a checksum error.
|
|
*/
|
|
|
|
eeprom_struct* get_seprom_ptr(void)
|
|
{
|
|
return seprom_data_ptr;
|
|
}
|
|
|
|
unsigned char* get_eeprom_mac_address(void)
|
|
{
|
|
return seprom_data_ptr->variant.eprom_struct.mac_Address;
|
|
}
|
|
|
|
/*
|
|
* ReadSProm, Physically reads data from the Serial PROM
|
|
*/
|
|
static void read_sprom(short address, int length, eeprom_struct *buffer)
|
|
{
|
|
short data = COMMAND_READ | (address & 0x3F);
|
|
short bit;
|
|
int i;
|
|
|
|
select_eeprom();
|
|
|
|
// Clock in 9 bits of the command
|
|
for (i = 0, bit = 0x100; i < 9; i++, bit >>= 1) {
|
|
if (data & bit)
|
|
*port_e_ptr |= HwPortESepromDIn;
|
|
else
|
|
*port_e_ptr &= ~(HwPortESepromDIn);
|
|
|
|
toggle_seprom_clock();
|
|
}
|
|
|
|
//
|
|
// Now read one or more shorts of data from the Seprom
|
|
//
|
|
while (length-- > 0) {
|
|
data = 0;
|
|
|
|
// Read 16 bits at a time
|
|
for (i = 0; i < 16; i++) {
|
|
data <<= 1;
|
|
toggle_seprom_clock();
|
|
data |= *port_e_ptr & HwPortESepromDOut;
|
|
|
|
}
|
|
|
|
buffer->variant.eprom_short_data[address++] = data;
|
|
}
|
|
|
|
deselect_eeprom();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* ReadSerialPROM
|
|
*
|
|
* Input: Pointer to array of 64 x 16 Bits
|
|
*
|
|
* Output: if no problem reading data is filled in
|
|
*/
|
|
static void read_serial_prom(eeprom_struct *data)
|
|
{
|
|
read_sprom(0, 64, data);
|
|
}
|
|
|
|
|
|
//
|
|
// Compute Serial EEPROM checksum
|
|
//
|
|
// Input: Pointer to struct with Eprom data
|
|
//
|
|
// Output: The computed Eprom checksum
|
|
//
|
|
static short compute_seprom_checksum(eeprom_struct *data)
|
|
{
|
|
short checksum = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < 126; i++) {
|
|
checksum += (short)data->variant.eprom_byte_data[i];
|
|
}
|
|
|
|
return((short)(0x5555 - (checksum & 0xFFFF)));
|
|
}
|
|
|
|
//
|
|
// Make sure the data port bits for the SEPROM are correctly initialised
|
|
//
|
|
|
|
void __init seprom_init(void)
|
|
{
|
|
short checksum;
|
|
|
|
// Init Port D
|
|
*(char *)(CLPS7111_VIRT_BASE + PDDDR) = 0x0;
|
|
*(char *)(CLPS7111_VIRT_BASE + PDDR) = 0x15;
|
|
|
|
// Init Port E
|
|
*(int *)(CLPS7111_VIRT_BASE + PEDDR) = 0x06;
|
|
*(int *)(CLPS7111_VIRT_BASE + PEDR) = 0x04;
|
|
|
|
//
|
|
// Make sure that EEPROM struct size never exceeds 128 bytes
|
|
//
|
|
if (sizeof(eeprom_struct) > 128) {
|
|
panic("Serial PROM struct size > 128, aborting read\n");
|
|
}
|
|
|
|
read_serial_prom(&seprom_data);
|
|
|
|
checksum = compute_seprom_checksum(&seprom_data);
|
|
|
|
if (checksum != seprom_data.variant.eprom_short_data[63]) {
|
|
panic("Serial EEPROM checksum failed\n");
|
|
}
|
|
|
|
seprom_data_ptr = &seprom_data;
|
|
}
|
|
|