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