1 /* $NetBSD: spd.c,v 1.1 2001/10/16 15:38:35 uch 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 struct cfattach spd_ca = { 70 sizeof(struct device), spd_match, spd_attach 71 }; 72 73 #ifdef DEBUG 74 #define LEGAL_SLOT(slot) ((slot) >= 0 && (slot) < 2) 75 #endif 76 77 int 78 spd_match(struct device *parent, struct cfdata *cf, void *aux) 79 { 80 81 return ((BOOTINFO_REF(BOOTINFO_DEVCONF) == 82 BOOTINFO_DEVCONF_SPD_PRESENT)); 83 } 84 85 void 86 spd_attach(struct device *parent, struct device *self, void *aux) 87 { 88 struct spd_attach_args spa; 89 90 printf(": PlayStation 2 HDD Unit\n"); 91 92 switch (BOOTINFO_REF(BOOTINFO_PCMCIA_TYPE)) { 93 default: 94 __spd_table[0].name = "<unknown product>"; 95 break; 96 case 0: 97 /* FALLTHROUGH */ 98 case 1: 99 /* FALLTHROUGH */ 100 case 2: 101 __spd_table[SPD_HDD].name = "SCPH-20400"; 102 __spd_table[SPD_NIC].name = "SCPH-10190"; 103 break; 104 case 3: 105 __spd_table[SPD_HDD].name = "SCPH-10260"; 106 __spd_table[SPD_NIC].name = "SCPH-10260"; 107 break; 108 } 109 110 /* disable all */ 111 _reg_write_2(SPD_INTR_ENABLE_REG16, 0); 112 _reg_write_2(SPD_INTR_CLEAR_REG16, _reg_read_2(SPD_INTR_STATUS_REG16)); 113 114 spa.spa_slot = SPD_HDD; 115 spa.spa_product_name = __spd_table[SPD_HDD].name; 116 config_found(self, &spa, spd_print); 117 118 spa.spa_slot = SPD_NIC; 119 spa.spa_product_name = __spd_table[SPD_NIC].name; 120 config_found(self, &spa, spd_print); 121 122 sbus_intr_establish(SBUS_IRQ_PCMCIA, spd_intr, 0); 123 } 124 125 int 126 spd_print(void *aux, const char *pnp) 127 { 128 struct spd_attach_args *spa = aux; 129 130 if (pnp) 131 printf("%s at %s", __spd_table[spa->spa_slot].name, pnp); 132 133 return (UNCONF); 134 } 135 136 int 137 spd_intr(void *arg) 138 { 139 u_int16_t r; 140 141 r = _reg_read_2(SPD_INTR_STATUS_REG16); 142 143 /* HDD (SCPH-20400) */ 144 if ((r & SPD_INTR_HDD) != 0) 145 if (__spd_table[SPD_HDD].func != NULL) 146 (*__spd_table[SPD_HDD].func)(__spd_table[SPD_HDD].arg); 147 148 /* Network (SCPH-10190) */ 149 if ((r & (SPD_INTR_EMAC3 | SPD_INTR_RXEND | SPD_INTR_TXEND | 150 SPD_INTR_RXDNV | SPD_INTR_TXDNV)) != 0) 151 if (__spd_table[SPD_NIC].func) 152 (*__spd_table[SPD_NIC].func)(__spd_table[SPD_NIC].arg); 153 154 /* reinstall */ 155 r = _reg_read_2(SPD_INTR_ENABLE_REG16); 156 _reg_write_2(SPD_INTR_ENABLE_REG16, 0); 157 _reg_write_2(SPD_INTR_ENABLE_REG16, r); 158 159 return (1); 160 } 161 162 void * 163 spd_intr_establish(enum spd_slot slot, int (*func)(void *), void *arg) 164 { 165 166 KDASSERT(LEGAL_SLOT(slot)); 167 KDASSERT(__spd_table[slot].func == 0); 168 169 __spd_table[slot].func = func; 170 __spd_table[slot].arg = arg; 171 172 return ((void *)slot); 173 } 174 175 void 176 spd_intr_disestablish(void *handle) 177 { 178 int slot = (int)handle; 179 180 KDASSERT(LEGAL_SLOT(slot)); 181 182 __spd_table[slot].func = 0; 183 } 184 185 /* 186 * EEPROM access 187 */ 188 void 189 spd_eeprom_read(int addr, u_int16_t *data, int n) 190 { 191 int i, j, s; 192 u_int8_t r; 193 194 s = _intr_suspend(); 195 196 /* set direction */ 197 _reg_write_1(SPD_IO_DIR_REG8, SPD_IO_CLK | SPD_IO_CS | SPD_IO_IN); 198 199 /* chip select high */ 200 r = 0; 201 _reg_write_1(SPD_IO_DATA_REG8, r); 202 delay(1); 203 r |= SPD_IO_CS; 204 r &= ~(SPD_IO_IN | SPD_IO_CLK); 205 _reg_write_1(SPD_IO_DATA_REG8, r); 206 delay(1); 207 208 /* put start bit */ 209 __spd_eeprom_out(&r, 1); 210 211 /* put op code (read) */ 212 __spd_eeprom_out(&r, 1); 213 __spd_eeprom_out(&r, 0); 214 215 /* set address */ 216 for (i = 0; i < 6; i++, addr <<= 1) 217 __spd_eeprom_out(&r, addr & 0x20); 218 219 /* get data */ 220 for (i = 0; i < n; i++, data++) 221 for (*data = 0, j = 15; j >= 0; j--) 222 *data |= (__spd_eeprom_in(&r) << j); 223 224 /* chip select low */ 225 r &= ~(SPD_IO_CS | SPD_IO_IN | SPD_IO_CLK); 226 _reg_write_1(SPD_IO_DATA_REG8, r); 227 delay(2); 228 229 _intr_resume(s); 230 } 231 232 void 233 __spd_eeprom_out(u_int8_t *rp, int onoff) 234 { 235 u_int8_t r = *rp; 236 237 if (onoff) 238 r |= SPD_IO_IN; 239 else 240 r &= ~SPD_IO_IN; 241 242 r &= ~SPD_IO_CLK; 243 _reg_write_1(SPD_IO_DATA_REG8, r); 244 delay(1); 245 246 r |= SPD_IO_CLK; 247 _reg_write_1(SPD_IO_DATA_REG8, r); 248 delay(1); 249 250 r &= ~SPD_IO_CLK; 251 _reg_write_1(SPD_IO_DATA_REG8, r); 252 delay(1); 253 254 *rp = r; 255 } 256 257 int 258 __spd_eeprom_in(u_int8_t *rp) 259 { 260 int ret; 261 u_int8_t r = *rp; 262 263 r &= ~(SPD_IO_IN | SPD_IO_CLK); 264 _reg_write_1(SPD_IO_DATA_REG8, r); 265 delay(1); 266 267 r |= SPD_IO_CLK; 268 _reg_write_1(SPD_IO_DATA_REG8, r); 269 delay(1); 270 ret = (_reg_read_1(SPD_IO_DATA_REG8) >> 4) & 0x1; 271 272 r &= ~SPD_IO_CLK; 273 _reg_write_1(SPD_IO_DATA_REG8, r); 274 delay(1); 275 276 *rp = r; 277 278 return (ret); 279 } 280 281