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