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