xref: /netbsd/sys/arch/playstation2/dev/spd.c (revision c4a72b64)
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