162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ip22-nvram.c: NVRAM and serial EEPROM handling. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/export.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/sgi/hpc3.h> 1062306a36Sopenharmony_ci#include <asm/sgi/ip22.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* Control opcode for serial eeprom */ 1362306a36Sopenharmony_ci#define EEPROM_READ 0xc000 /* serial memory read */ 1462306a36Sopenharmony_ci#define EEPROM_WEN 0x9800 /* write enable before prog modes */ 1562306a36Sopenharmony_ci#define EEPROM_WRITE 0xa000 /* serial memory write */ 1662306a36Sopenharmony_ci#define EEPROM_WRALL 0x8800 /* write all registers */ 1762306a36Sopenharmony_ci#define EEPROM_WDS 0x8000 /* disable all programming */ 1862306a36Sopenharmony_ci#define EEPROM_PRREAD 0xc000 /* read protect register */ 1962306a36Sopenharmony_ci#define EEPROM_PREN 0x9800 /* enable protect register mode */ 2062306a36Sopenharmony_ci#define EEPROM_PRCLEAR 0xffff /* clear protect register */ 2162306a36Sopenharmony_ci#define EEPROM_PRWRITE 0xa000 /* write protect register */ 2262306a36Sopenharmony_ci#define EEPROM_PRDS 0x8000 /* disable protect register, forever */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define EEPROM_EPROT 0x01 /* Protect register enable */ 2562306a36Sopenharmony_ci#define EEPROM_CSEL 0x02 /* Chip select */ 2662306a36Sopenharmony_ci#define EEPROM_ECLK 0x04 /* EEPROM clock */ 2762306a36Sopenharmony_ci#define EEPROM_DATO 0x08 /* Data out */ 2862306a36Sopenharmony_ci#define EEPROM_DATI 0x10 /* Data in */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* We need to use these functions early... */ 3162306a36Sopenharmony_ci#define delay() ({ \ 3262306a36Sopenharmony_ci int x; \ 3362306a36Sopenharmony_ci for (x=0; x<100000; x++) __asm__ __volatile__(""); }) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define eeprom_cs_on(ptr) ({ \ 3662306a36Sopenharmony_ci __raw_writel(__raw_readl(ptr) & ~EEPROM_DATO, ptr); \ 3762306a36Sopenharmony_ci __raw_writel(__raw_readl(ptr) & ~EEPROM_ECLK, ptr); \ 3862306a36Sopenharmony_ci __raw_writel(__raw_readl(ptr) & ~EEPROM_EPROT, ptr); \ 3962306a36Sopenharmony_ci delay(); \ 4062306a36Sopenharmony_ci __raw_writel(__raw_readl(ptr) | EEPROM_CSEL, ptr); \ 4162306a36Sopenharmony_ci __raw_writel(__raw_readl(ptr) | EEPROM_ECLK, ptr); }) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define eeprom_cs_off(ptr) ({ \ 4562306a36Sopenharmony_ci __raw_writel(__raw_readl(ptr) & ~EEPROM_ECLK, ptr); \ 4662306a36Sopenharmony_ci __raw_writel(__raw_readl(ptr) & ~EEPROM_CSEL, ptr); \ 4762306a36Sopenharmony_ci __raw_writel(__raw_readl(ptr) | EEPROM_EPROT, ptr); \ 4862306a36Sopenharmony_ci __raw_writel(__raw_readl(ptr) | EEPROM_ECLK, ptr); }) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define BITS_IN_COMMAND 11 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * clock in the nvram command and the register number. For the 5362306a36Sopenharmony_ci * national semiconductor nv ram chip the op code is 3 bits and 5462306a36Sopenharmony_ci * the address is 6/8 bits. 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_cistatic inline void eeprom_cmd(unsigned int *ctrl, unsigned cmd, unsigned reg) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci unsigned short ser_cmd; 5962306a36Sopenharmony_ci int i; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci ser_cmd = cmd | (reg << (16 - BITS_IN_COMMAND)); 6262306a36Sopenharmony_ci for (i = 0; i < BITS_IN_COMMAND; i++) { 6362306a36Sopenharmony_ci if (ser_cmd & (1<<15)) /* if high order bit set */ 6462306a36Sopenharmony_ci __raw_writel(__raw_readl(ctrl) | EEPROM_DATO, ctrl); 6562306a36Sopenharmony_ci else 6662306a36Sopenharmony_ci __raw_writel(__raw_readl(ctrl) & ~EEPROM_DATO, ctrl); 6762306a36Sopenharmony_ci __raw_writel(__raw_readl(ctrl) & ~EEPROM_ECLK, ctrl); 6862306a36Sopenharmony_ci delay(); 6962306a36Sopenharmony_ci __raw_writel(__raw_readl(ctrl) | EEPROM_ECLK, ctrl); 7062306a36Sopenharmony_ci delay(); 7162306a36Sopenharmony_ci ser_cmd <<= 1; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci /* see data sheet timing diagram */ 7462306a36Sopenharmony_ci __raw_writel(__raw_readl(ctrl) & ~EEPROM_DATO, ctrl); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciunsigned short ip22_eeprom_read(unsigned int *ctrl, int reg) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci unsigned short res = 0; 8062306a36Sopenharmony_ci int i; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci __raw_writel(__raw_readl(ctrl) & ~EEPROM_EPROT, ctrl); 8362306a36Sopenharmony_ci eeprom_cs_on(ctrl); 8462306a36Sopenharmony_ci eeprom_cmd(ctrl, EEPROM_READ, reg); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* clock the data ouf of serial mem */ 8762306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 8862306a36Sopenharmony_ci __raw_writel(__raw_readl(ctrl) & ~EEPROM_ECLK, ctrl); 8962306a36Sopenharmony_ci delay(); 9062306a36Sopenharmony_ci __raw_writel(__raw_readl(ctrl) | EEPROM_ECLK, ctrl); 9162306a36Sopenharmony_ci delay(); 9262306a36Sopenharmony_ci res <<= 1; 9362306a36Sopenharmony_ci if (__raw_readl(ctrl) & EEPROM_DATI) 9462306a36Sopenharmony_ci res |= 1; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci eeprom_cs_off(ctrl); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return res; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ciEXPORT_SYMBOL(ip22_eeprom_read); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* 10562306a36Sopenharmony_ci * Read specified register from main NVRAM 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ciunsigned short ip22_nvram_read(int reg) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci if (ip22_is_fullhouse()) 11062306a36Sopenharmony_ci /* IP22 (Indigo2 aka FullHouse) stores env variables into 11162306a36Sopenharmony_ci * 93CS56 Microwire Bus EEPROM 2048 Bit (128x16) */ 11262306a36Sopenharmony_ci return ip22_eeprom_read(&hpc3c0->eeprom, reg); 11362306a36Sopenharmony_ci else { 11462306a36Sopenharmony_ci unsigned short tmp; 11562306a36Sopenharmony_ci /* IP24 (Indy aka Guiness) uses DS1386 8K version */ 11662306a36Sopenharmony_ci reg <<= 1; 11762306a36Sopenharmony_ci tmp = hpc3c0->bbram[reg++] & 0xff; 11862306a36Sopenharmony_ci return (tmp << 8) | (hpc3c0->bbram[reg] & 0xff); 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciEXPORT_SYMBOL(ip22_nvram_read); 123