spd.c revision 1.3 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