1/* -*- linux-c -*- */ 2 3/* plx9050.c 4 * Copyright (C) 2000 by Francois Wautier 5 * based on code from Bjorn Davis 6 * 7 * Read and write command for the eprom attached to 8 * the PLX9050 9 */ 10 11/* Modifications and extensions 12 * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * as published by the Free Software Foundation; either version 17 * 2 of the License, or (at your option) any later version. 18 **/ 19 20/* We handle PCI devices */ 21#include <linux/pci.h> 22 23/* We need to use ioremap */ 24#include <asm/io.h> 25 26#include <linux/delay.h> 27 28 /* Joachim Martillo modified this file */ 29 /* so that it had no dependencies on specific */ 30 /* Aurora adapter card or ESSC* structures*/ 31 /* The original file use TRUE for 1 and */ 32 /* FALSE for 0. This convention conflicted */ 33 /* with other conventions throughout LINUX */ 34 /* also TRUE was used for setting an eprom */ 35 /* bit which is a slight semantic confusion. */ 36 /* I just used 0 and 1 */ 37#include "Reg9050.h" 38 39/* 40 * Write a single bit to the serial EPROM interface. 41 */ 42 43 /* eprom_ctl is the */ 44 /* address of the 9050 */ 45 /* eprom control register */ 46 /* The original & operation */ 47 /* looks wrong. I am surprised */ 48 /* the code worked */ 49 /* but I left the parentheses */ 50 /* because readl, writel etc */ 51 /* are macros*/ 52 53 /* The following function */ 54 /* assumes the proper bit */ 55 /* in the serial eprom */ 56 /* has already been selected*/ 57 58 /* The 9050 registers are 32 bits */ 59 /* hence the readl and writel */ 60 /* macros are invoked*/ 61 62 /* eprom_ctl must be a virtual */ 63 /* address*/ 64 65static void plx9050_eprom_wbit(unsigned int* eprom_ctl, unsigned int val) 66{ 67 unsigned int ctrl; 68 69 /* get the initial value of the CTRL register */ 70 ctrl = readl((eprom_ctl)); 71 72 /* set or clear the data bit */ 73 if (val) 74 { 75 ctrl |= PLX_CTRL_SEPWD; 76 } 77 else 78 { 79 ctrl &= ~PLX_CTRL_SEPWD; 80 } 81 82 writel(ctrl, (eprom_ctl)); 83 84 udelay(1); 85 86 /* Toggle the clock line */ 87 /* gets to the next bit */ 88 /* in the serial eprom */ 89 ctrl |= PLX_CTRL_SEPCLK; 90 writel(ctrl, (eprom_ctl)); 91 92 udelay(1); 93 94 /* Toggle the clock line */ 95 ctrl &= ~PLX_CTRL_SEPCLK; 96 writel(ctrl, (eprom_ctl)); 97 udelay(1); 98} 99 100/* 101 * Run a serial EPROM command. Returns 1 on success, 102 * 0 otherwise. 103 */ 104 105/* This routine does the write of data but only sets up */ 106/* for a read*/ 107/* the write goes from most significant to least significant */ 108unsigned int plx9050_eprom_cmd(unsigned int* eprom_ctl, unsigned char cmd, unsigned char addr, unsigned short data) 109{ 110 unsigned int ctrl; 111 unsigned char shiftb; 112 unsigned short shiftw; 113 unsigned int l, v; 114 unsigned char ret; 115 int i; 116 117 ret = 1; 118 shiftb = addr << (NM93_BITS_PER_BYTE - NM93_ADDRBITS); /* looks a bizarre way to mask out unused bits */ 119 120 ctrl = readl((eprom_ctl)); 121 122 ctrl &= ~(PLX_CTRL_SEPCLK | PLX_CTRL_SEPWD); 123 writel(ctrl, (eprom_ctl)); 124 udelay(1); 125 126 ctrl |= PLX_CTRL_SEPCS; 127 writel(ctrl, (eprom_ctl)); 128 129 plx9050_eprom_wbit(eprom_ctl, 1); 130 131 /* 132 * Clock out the command 133 */ 134 135 plx9050_eprom_wbit(eprom_ctl, (cmd & 0x02) != 0); 136 plx9050_eprom_wbit(eprom_ctl, (cmd & 0x01) != 0); 137 138 /* 139 * Clock out the address 140 */ 141 142 i = NM93_ADDRBITS; 143 while (i != 0) /* here we get to the correct */ 144 /* short in the serial eprom*/ 145 { 146 /* printf("Loop #1\n"); */ 147 plx9050_eprom_wbit(eprom_ctl, (shiftb & 0x80) != 0); 148 149 shiftb <<= 1; 150 i--; 151 } 152 153 if (cmd == NM93_WRITECMD) /* now do the write if */ 154 /* a write is to be done*/ 155 { 156 /* write data? */ 157 /* 158 * Clock out the data 159 */ 160 161 shiftw = data; 162 163 i = NM93_BITS_PER_WORD; 164 while (i != 0) { 165 /* printf("Loop #2\n"); */ 166 plx9050_eprom_wbit(eprom_ctl, (shiftw & 0x8000) != 0); 167 168 shiftw <<= 1; 169 i--; 170 } 171 172 /* 173 * De-assert chip select for a short period of time 174 */ 175 ctrl = readl((eprom_ctl)); 176 177 ctrl &= ~PLX_CTRL_SEPCS; 178 writel(ctrl, (eprom_ctl)); 179 udelay(2); 180 181 /* 182 * Re-assert chip select 183 */ 184 ctrl |= PLX_CTRL_SEPCS; 185 writel(ctrl, (eprom_ctl)); 186 187 /* 188 * Wait for a low to high transition of DO 189 */ 190 191 i = 20000; 192 ctrl = readl((eprom_ctl)); 193 l = (ctrl & PLX_CTRL_SEPRD); 194 195 while (i != 0) 196 { 197 /* printf("Loop #3\n"); */ 198 ctrl = readl((eprom_ctl)); 199 v = (ctrl & PLX_CTRL_SEPRD); 200 if (v != 0 && l == 0) 201 { 202 break; 203 } 204 l = v; 205 udelay(1); 206 i--; 207 } 208 209 if (i == 0) 210 { 211 printk("plx9050: eprom didn't go low to high"); 212 ret = 0; 213 } 214 } 215 216 if (cmd != NM93_READCMD) /* not a read -- terminate */ 217 { 218 /* 219 * De-assert the chip select. 220 */ 221 222 ctrl = readl((eprom_ctl)); 223 ctrl &= ~PLX_CTRL_SEPCS; 224 writel(ctrl,(eprom_ctl)); 225 } 226 /* otherwise left in read state */ 227 return ret; 228} 229 230/* 231 * Read the serial EPROM. Returns 1 on success, 0 on failure. 232 * reads in shorts (i.e., 16 bits at a time.) 233 * 234 */ 235 236unsigned int 237plx9050_eprom_read(unsigned int* eprom_ctl, unsigned short *ptr, unsigned char addr, unsigned short len) 238{ 239 unsigned short shiftw; 240 int i; 241 unsigned int ctrl; 242 243 if (!plx9050_eprom_cmd(eprom_ctl, NM93_READCMD, addr, (unsigned short) 0x0)) /* set up read */ 244 { 245 return 0; 246 } 247 248 ctrl = readl((eprom_ctl)); /* synchronize */ 249 250 while (len-- > 0) /* now read one word at a time */ 251 { 252 shiftw = 0; 253 254 ctrl &= ~PLX_CTRL_SEPCLK; 255 writel(ctrl, (eprom_ctl)); 256 257 udelay(1); 258 259 i = NM93_BITS_PER_WORD; 260 while (1) /* now read one bit at a time, */ 261 /* left shifting each bit */ 262 { 263 ctrl |= PLX_CTRL_SEPCLK; 264 writel(ctrl, (eprom_ctl)); 265 266 udelay(1); 267 268 ctrl = readl((eprom_ctl)); 269 270 271 if ((ctrl & PLX_CTRL_SEPRD) != 0) 272 { 273 shiftw |= 0x1; 274 } 275 276 i--; 277 if (i == 0) 278 { 279 break; 280 } 281 shiftw <<= 1; 282 283 ctrl &= ~PLX_CTRL_SEPCLK; 284 writel(ctrl, (eprom_ctl)); 285 udelay(1); 286 } 287 288 *ptr++ = shiftw; 289 } 290 291 ctrl &= ~PLX_CTRL_SEPCS; 292 writel(ctrl, (eprom_ctl)); 293 294 udelay(1); 295 ctrl &= ~PLX_CTRL_SEPCLK; 296 writel(ctrl, (eprom_ctl)); 297 298 return 1; 299} 300