1 /* $NetBSD: spd.c,v 1.3 2002/10/02 04:17:21 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 42 #include <machine/bootinfo.h> 43 44 #include <playstation2/ee/eevar.h> 45 #include <playstation2/dev/sbusvar.h> 46 #include <playstation2/dev/spdvar.h> 47 #include <playstation2/dev/spdreg.h> 48 49 #ifdef DEBUG 50 #define STATIC 51 #else 52 #define STATIC static 53 #endif 54 55 STATIC int spd_match(struct device *, struct cfdata *, void *); 56 STATIC void spd_attach(struct device *, struct device *, void *); 57 STATIC int spd_print(void *, const char *); 58 STATIC int spd_intr(void *); 59 STATIC void __spd_eeprom_out(u_int8_t *, int); 60 STATIC int __spd_eeprom_in(u_int8_t *); 61 62 /* SPD device can't attach twice. because PS2 PC-Card slot is only one. */ 63 STATIC struct { 64 int (*func)(void *); 65 void *arg; 66 const char *name; 67 } __spd_table[2]; 68 69 CFATTACH_DECL(spd, sizeof(struct device), 70 spd_match, spd_attach, NULL, NULL); 71 72 #ifdef DEBUG 73 #define LEGAL_SLOT(slot) ((slot) >= 0 && (slot) < 2) 74 #endif 75 76 int 77 spd_match(struct device *parent, struct cfdata *cf, void *aux) 78 { 79 80 return ((BOOTINFO_REF(BOOTINFO_DEVCONF) == 81 BOOTINFO_DEVCONF_SPD_PRESENT)); 82 } 83 84 void 85 spd_attach(struct device *parent, struct device *self, void *aux) 86 { 87 struct spd_attach_args spa; 88 89 printf(": PlayStation 2 HDD Unit\n"); 90 91 switch (BOOTINFO_REF(BOOTINFO_PCMCIA_TYPE)) { 92 default: 93 __spd_table[0].name = "<unknown product>"; 94 break; 95 case 0: 96 /* FALLTHROUGH */ 97 case 1: 98 /* FALLTHROUGH */ 99 case 2: 100 __spd_table[SPD_HDD].name = "SCPH-20400"; 101 __spd_table[SPD_NIC].name = "SCPH-10190"; 102 break; 103 case 3: 104 __spd_table[SPD_HDD].name = "SCPH-10260"; 105 __spd_table[SPD_NIC].name = "SCPH-10260"; 106 break; 107 } 108 109 /* disable all */ 110 _reg_write_2(SPD_INTR_ENABLE_REG16, 0); 111 _reg_write_2(SPD_INTR_CLEAR_REG16, _reg_read_2(SPD_INTR_STATUS_REG16)); 112 113 spa.spa_slot = SPD_HDD; 114 spa.spa_product_name = __spd_table[SPD_HDD].name; 115 config_found(self, &spa, spd_print); 116 117 spa.spa_slot = SPD_NIC; 118 spa.spa_product_name = __spd_table[SPD_NIC].name; 119 config_found(self, &spa, spd_print); 120 121 sbus_intr_establish(SBUS_IRQ_PCMCIA, spd_intr, 0); 122 } 123 124 int 125 spd_print(void *aux, const char *pnp) 126 { 127 struct spd_attach_args *spa = aux; 128 129 if (pnp) 130 printf("%s at %s", __spd_table[spa->spa_slot].name, pnp); 131 132 return (UNCONF); 133 } 134 135 int 136 spd_intr(void *arg) 137 { 138 u_int16_t r; 139 140 r = _reg_read_2(SPD_INTR_STATUS_REG16); 141 142 /* HDD (SCPH-20400) */ 143 if ((r & SPD_INTR_HDD) != 0) 144 if (__spd_table[SPD_HDD].func != NULL) 145 (*__spd_table[SPD_HDD].func)(__spd_table[SPD_HDD].arg); 146 147 /* Network (SCPH-10190) */ 148 if ((r & (SPD_INTR_EMAC3 | SPD_INTR_RXEND | SPD_INTR_TXEND | 149 SPD_INTR_RXDNV | SPD_INTR_TXDNV)) != 0) 150 if (__spd_table[SPD_NIC].func) 151 (*__spd_table[SPD_NIC].func)(__spd_table[SPD_NIC].arg); 152 153 /* reinstall */ 154 r = _reg_read_2(SPD_INTR_ENABLE_REG16); 155 _reg_write_2(SPD_INTR_ENABLE_REG16, 0); 156 _reg_write_2(SPD_INTR_ENABLE_REG16, r); 157 158 return (1); 159 } 160 161 void * 162 spd_intr_establish(enum spd_slot slot, int (*func)(void *), void *arg) 163 { 164 165 KDASSERT(LEGAL_SLOT(slot)); 166 KDASSERT(__spd_table[slot].func == 0); 167 168 __spd_table[slot].func = func; 169 __spd_table[slot].arg = arg; 170 171 return ((void *)slot); 172 } 173 174 void 175 spd_intr_disestablish(void *handle) 176 { 177 int slot = (int)handle; 178 179 KDASSERT(LEGAL_SLOT(slot)); 180 181 __spd_table[slot].func = 0; 182 } 183 184 /* 185 * EEPROM access 186 */ 187 void 188 spd_eeprom_read(int addr, u_int16_t *data, int n) 189 { 190 int i, j, s; 191 u_int8_t r; 192 193 s = _intr_suspend(); 194 195 /* set direction */ 196 _reg_write_1(SPD_IO_DIR_REG8, SPD_IO_CLK | SPD_IO_CS | SPD_IO_IN); 197 198 /* chip select high */ 199 r = 0; 200 _reg_write_1(SPD_IO_DATA_REG8, r); 201 delay(1); 202 r |= SPD_IO_CS; 203 r &= ~(SPD_IO_IN | SPD_IO_CLK); 204 _reg_write_1(SPD_IO_DATA_REG8, r); 205 delay(1); 206 207 /* put start bit */ 208 __spd_eeprom_out(&r, 1); 209 210 /* put op code (read) */ 211 __spd_eeprom_out(&r, 1); 212 __spd_eeprom_out(&r, 0); 213 214 /* set address */ 215 for (i = 0; i < 6; i++, addr <<= 1) 216 __spd_eeprom_out(&r, addr & 0x20); 217 218 /* get data */ 219 for (i = 0; i < n; i++, data++) 220 for (*data = 0, j = 15; j >= 0; j--) 221 *data |= (__spd_eeprom_in(&r) << j); 222 223 /* chip select low */ 224 r &= ~(SPD_IO_CS | SPD_IO_IN | SPD_IO_CLK); 225 _reg_write_1(SPD_IO_DATA_REG8, r); 226 delay(2); 227 228 _intr_resume(s); 229 } 230 231 void 232 __spd_eeprom_out(u_int8_t *rp, int onoff) 233 { 234 u_int8_t r = *rp; 235 236 if (onoff) 237 r |= SPD_IO_IN; 238 else 239 r &= ~SPD_IO_IN; 240 241 r &= ~SPD_IO_CLK; 242 _reg_write_1(SPD_IO_DATA_REG8, r); 243 delay(1); 244 245 r |= SPD_IO_CLK; 246 _reg_write_1(SPD_IO_DATA_REG8, r); 247 delay(1); 248 249 r &= ~SPD_IO_CLK; 250 _reg_write_1(SPD_IO_DATA_REG8, r); 251 delay(1); 252 253 *rp = r; 254 } 255 256 int 257 __spd_eeprom_in(u_int8_t *rp) 258 { 259 int ret; 260 u_int8_t r = *rp; 261 262 r &= ~(SPD_IO_IN | SPD_IO_CLK); 263 _reg_write_1(SPD_IO_DATA_REG8, r); 264 delay(1); 265 266 r |= SPD_IO_CLK; 267 _reg_write_1(SPD_IO_DATA_REG8, r); 268 delay(1); 269 ret = (_reg_read_1(SPD_IO_DATA_REG8) >> 4) & 0x1; 270 271 r &= ~SPD_IO_CLK; 272 _reg_write_1(SPD_IO_DATA_REG8, r); 273 delay(1); 274 275 *rp = r; 276 277 return (ret); 278 } 279 280