162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * this file included by nicstar.c 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* 762306a36Sopenharmony_ci * nicstarmac.c 862306a36Sopenharmony_ci * Read this ForeRunner's MAC address from eprom/eeprom 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_citypedef void __iomem *virt_addr_t; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define CYCLE_DELAY 5 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define osp_MicroDelay(microsec) {unsigned long useconds = (microsec); \ 1862306a36Sopenharmony_ci udelay((useconds));} 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * The following tables represent the timing diagrams found in 2162306a36Sopenharmony_ci * the Data Sheet for the Xicor X25020 EEProm. The #defines below 2262306a36Sopenharmony_ci * represent the bits in the NICStAR's General Purpose register 2362306a36Sopenharmony_ci * that must be toggled for the corresponding actions on the EEProm 2462306a36Sopenharmony_ci * to occur. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Write Data To EEProm from SI line on rising edge of CLK */ 2862306a36Sopenharmony_ci/* Read Data From EEProm on falling edge of CLK */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define CS_HIGH 0x0002 /* Chip select high */ 3162306a36Sopenharmony_ci#define CS_LOW 0x0000 /* Chip select low (active low) */ 3262306a36Sopenharmony_ci#define CLK_HIGH 0x0004 /* Clock high */ 3362306a36Sopenharmony_ci#define CLK_LOW 0x0000 /* Clock low */ 3462306a36Sopenharmony_ci#define SI_HIGH 0x0001 /* Serial input data high */ 3562306a36Sopenharmony_ci#define SI_LOW 0x0000 /* Serial input data low */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Read Status Register = 0000 0101b */ 3862306a36Sopenharmony_ci#if 0 3962306a36Sopenharmony_cistatic u_int32_t rdsrtab[] = { 4062306a36Sopenharmony_ci CS_HIGH | CLK_HIGH, 4162306a36Sopenharmony_ci CS_LOW | CLK_LOW, 4262306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 4362306a36Sopenharmony_ci CLK_LOW, 4462306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 4562306a36Sopenharmony_ci CLK_LOW, 4662306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 4762306a36Sopenharmony_ci CLK_LOW, 4862306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 4962306a36Sopenharmony_ci CLK_LOW, 5062306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 5162306a36Sopenharmony_ci CLK_LOW | SI_HIGH, 5262306a36Sopenharmony_ci CLK_HIGH | SI_HIGH, /* 1 */ 5362306a36Sopenharmony_ci CLK_LOW | SI_LOW, 5462306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 5562306a36Sopenharmony_ci CLK_LOW | SI_HIGH, 5662306a36Sopenharmony_ci CLK_HIGH | SI_HIGH /* 1 */ 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci#endif /* 0 */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Read from EEPROM = 0000 0011b */ 6162306a36Sopenharmony_cistatic u_int32_t readtab[] = { 6262306a36Sopenharmony_ci /* 6362306a36Sopenharmony_ci CS_HIGH | CLK_HIGH, 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci CS_LOW | CLK_LOW, 6662306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 6762306a36Sopenharmony_ci CLK_LOW, 6862306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 6962306a36Sopenharmony_ci CLK_LOW, 7062306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 7162306a36Sopenharmony_ci CLK_LOW, 7262306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 7362306a36Sopenharmony_ci CLK_LOW, 7462306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 7562306a36Sopenharmony_ci CLK_LOW, 7662306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 7762306a36Sopenharmony_ci CLK_LOW | SI_HIGH, 7862306a36Sopenharmony_ci CLK_HIGH | SI_HIGH, /* 1 */ 7962306a36Sopenharmony_ci CLK_LOW | SI_HIGH, 8062306a36Sopenharmony_ci CLK_HIGH | SI_HIGH /* 1 */ 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* Clock to read from/write to the eeprom */ 8462306a36Sopenharmony_cistatic u_int32_t clocktab[] = { 8562306a36Sopenharmony_ci CLK_LOW, 8662306a36Sopenharmony_ci CLK_HIGH, 8762306a36Sopenharmony_ci CLK_LOW, 8862306a36Sopenharmony_ci CLK_HIGH, 8962306a36Sopenharmony_ci CLK_LOW, 9062306a36Sopenharmony_ci CLK_HIGH, 9162306a36Sopenharmony_ci CLK_LOW, 9262306a36Sopenharmony_ci CLK_HIGH, 9362306a36Sopenharmony_ci CLK_LOW, 9462306a36Sopenharmony_ci CLK_HIGH, 9562306a36Sopenharmony_ci CLK_LOW, 9662306a36Sopenharmony_ci CLK_HIGH, 9762306a36Sopenharmony_ci CLK_LOW, 9862306a36Sopenharmony_ci CLK_HIGH, 9962306a36Sopenharmony_ci CLK_LOW, 10062306a36Sopenharmony_ci CLK_HIGH, 10162306a36Sopenharmony_ci CLK_LOW 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define NICSTAR_REG_WRITE(bs, reg, val) \ 10562306a36Sopenharmony_ci while ( readl(bs + STAT) & 0x0200 ) ; \ 10662306a36Sopenharmony_ci writel((val),(base)+(reg)) 10762306a36Sopenharmony_ci#define NICSTAR_REG_READ(bs, reg) \ 10862306a36Sopenharmony_ci readl((base)+(reg)) 10962306a36Sopenharmony_ci#define NICSTAR_REG_GENERAL_PURPOSE GP 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci * This routine will clock the Read_Status_reg function into the X2520 11362306a36Sopenharmony_ci * eeprom, then pull the result from bit 16 of the NicSTaR's General Purpose 11462306a36Sopenharmony_ci * register. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci#if 0 11762306a36Sopenharmony_ciu_int32_t nicstar_read_eprom_status(virt_addr_t base) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci u_int32_t val; 12062306a36Sopenharmony_ci u_int32_t rbyte; 12162306a36Sopenharmony_ci int32_t i, j; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* Send read instruction */ 12462306a36Sopenharmony_ci val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) { 12762306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 12862306a36Sopenharmony_ci (val | rdsrtab[i])); 12962306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Done sending instruction - now pull data off of bit 16, MSB first */ 13362306a36Sopenharmony_ci /* Data clocked out of eeprom on falling edge of clock */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci rbyte = 0; 13662306a36Sopenharmony_ci for (i = 7, j = 0; i >= 0; i--) { 13762306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 13862306a36Sopenharmony_ci (val | clocktab[j++])); 13962306a36Sopenharmony_ci rbyte |= (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) 14062306a36Sopenharmony_ci & 0x00010000) >> 16) << i); 14162306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 14262306a36Sopenharmony_ci (val | clocktab[j++])); 14362306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2); 14662306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 14762306a36Sopenharmony_ci return rbyte; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci#endif /* 0 */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* 15262306a36Sopenharmony_ci * This routine will clock the Read_data function into the X2520 15362306a36Sopenharmony_ci * eeprom, followed by the address to read from, through the NicSTaR's General 15462306a36Sopenharmony_ci * Purpose register. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic u_int8_t read_eprom_byte(virt_addr_t base, u_int8_t offset) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci u_int32_t val = 0; 16062306a36Sopenharmony_ci int i, j = 0; 16162306a36Sopenharmony_ci u_int8_t tempread = 0; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Send READ instruction */ 16662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(readtab); i++) { 16762306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 16862306a36Sopenharmony_ci (val | readtab[i])); 16962306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Next, we need to send the byte address to read from */ 17362306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 17462306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 17562306a36Sopenharmony_ci (val | clocktab[j++] | ((offset >> i) & 1))); 17662306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 17762306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 17862306a36Sopenharmony_ci (val | clocktab[j++] | ((offset >> i) & 1))); 17962306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci j = 0; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* Now, we can read data from the eeprom by clocking it in */ 18562306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 18662306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 18762306a36Sopenharmony_ci (val | clocktab[j++])); 18862306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 18962306a36Sopenharmony_ci tempread |= 19062306a36Sopenharmony_ci (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) 19162306a36Sopenharmony_ci & 0x00010000) >> 16) << i); 19262306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 19362306a36Sopenharmony_ci (val | clocktab[j++])); 19462306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2); 19862306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 19962306a36Sopenharmony_ci return tempread; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void nicstar_init_eprom(virt_addr_t base) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci u_int32_t val; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * turn chip select off 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_ci val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 21262306a36Sopenharmony_ci (val | CS_HIGH | CLK_HIGH)); 21362306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 21662306a36Sopenharmony_ci (val | CS_HIGH | CLK_LOW)); 21762306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 22062306a36Sopenharmony_ci (val | CS_HIGH | CLK_HIGH)); 22162306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 22462306a36Sopenharmony_ci (val | CS_HIGH | CLK_LOW)); 22562306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/* 22962306a36Sopenharmony_ci * This routine will be the interface to the ReadPromByte function 23062306a36Sopenharmony_ci * above. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void 23462306a36Sopenharmony_cinicstar_read_eprom(virt_addr_t base, 23562306a36Sopenharmony_ci u_int8_t prom_offset, u_int8_t * buffer, u_int32_t nbytes) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci u_int i; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci for (i = 0; i < nbytes; i++) { 24062306a36Sopenharmony_ci buffer[i] = read_eprom_byte(base, prom_offset); 24162306a36Sopenharmony_ci ++prom_offset; 24262306a36Sopenharmony_ci osp_MicroDelay(CYCLE_DELAY); 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci} 245