xref: /freebsd-src/sys/powerpc/psim/ata_iobus.c (revision 18250ec6c089c0c50cbd9fd87d78e03ff89916df)
160727d8bSWarner Losh /*-
271e3c308SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
371e3c308SPedro F. Giffuni  *
48860e8c6SPeter Grehan  * Copyright 2002 by Peter Grehan. All rights reserved.
58860e8c6SPeter Grehan  *
68860e8c6SPeter Grehan  * Redistribution and use in source and binary forms, with or without
78860e8c6SPeter Grehan  * modification, are permitted provided that the following conditions
88860e8c6SPeter Grehan  * are met:
98860e8c6SPeter Grehan  * 1. Redistributions of source code must retain the above copyright
108860e8c6SPeter Grehan  *    notice, this list of conditions and the following disclaimer.
118860e8c6SPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
128860e8c6SPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
138860e8c6SPeter Grehan  *    documentation and/or other materials provided with the distribution.
148860e8c6SPeter Grehan  * 3. The name of the author may not be used to endorse or promote products
158860e8c6SPeter Grehan  *    derived from this software without specific prior written permission.
168860e8c6SPeter Grehan  *
178860e8c6SPeter Grehan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
188860e8c6SPeter Grehan  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
198860e8c6SPeter Grehan  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
208860e8c6SPeter Grehan  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
218860e8c6SPeter Grehan  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
228860e8c6SPeter Grehan  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
238860e8c6SPeter Grehan  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
248860e8c6SPeter Grehan  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
258860e8c6SPeter Grehan  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
268860e8c6SPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
278860e8c6SPeter Grehan  * SUCH DAMAGE.
288860e8c6SPeter Grehan  */
298860e8c6SPeter Grehan 
30d2ce15bdSMarius Strobl #include <sys/cdefs.h>
318860e8c6SPeter Grehan /*
328860e8c6SPeter Grehan  * PSIM local bus ATA controller
338860e8c6SPeter Grehan  */
348860e8c6SPeter Grehan #include <sys/param.h>
358860e8c6SPeter Grehan #include <sys/systm.h>
368860e8c6SPeter Grehan #include <sys/kernel.h>
378860e8c6SPeter Grehan #include <sys/module.h>
388860e8c6SPeter Grehan #include <sys/bus.h>
398860e8c6SPeter Grehan #include <sys/malloc.h>
40c576427cSPeter Grehan #include <sys/sema.h>
41250fe3a6SPeter Grehan #include <sys/taskqueue.h>
428860e8c6SPeter Grehan #include <machine/stdarg.h>
43ec9db415SPeter Grehan #include <vm/uma.h>
448860e8c6SPeter Grehan #include <machine/resource.h>
458860e8c6SPeter Grehan #include <machine/bus.h>
468860e8c6SPeter Grehan #include <sys/rman.h>
47597dc663SPeter Grehan #include <sys/ata.h>
488860e8c6SPeter Grehan #include <dev/ata/ata-all.h>
4998cbfce5SPeter Grehan #include <ata_if.h>
508860e8c6SPeter Grehan 
518860e8c6SPeter Grehan #include <dev/ofw/openfirm.h>
528860e8c6SPeter Grehan #include <powerpc/psim/iobusvar.h>
538860e8c6SPeter Grehan 
548860e8c6SPeter Grehan /*
558860e8c6SPeter Grehan  * Define the iobus ata bus attachment. This creates a pseudo-bus that
568860e8c6SPeter Grehan  * the ATA device can be attached to
578860e8c6SPeter Grehan  */
588860e8c6SPeter Grehan static  int  ata_iobus_attach(device_t dev);
598860e8c6SPeter Grehan static  int  ata_iobus_probe(device_t dev);
608860e8c6SPeter Grehan static  int  ata_iobus_print_child(device_t dev, device_t child);
618860e8c6SPeter Grehan struct resource *ata_iobus_alloc_resource(device_t, device_t, int, int *,
622dd1bdf1SJustin Hibbits 					  rman_res_t, rman_res_t, rman_res_t,
632dd1bdf1SJustin Hibbits 					  u_int);
649dbf5b0eSJohn Baldwin static int ata_iobus_release_resource(device_t, device_t, struct resource *);
658860e8c6SPeter Grehan 
668860e8c6SPeter Grehan static device_method_t ata_iobus_methods[] = {
678860e8c6SPeter Grehan         /* Device interface */
688860e8c6SPeter Grehan 	DEVMETHOD(device_probe,		ata_iobus_probe),
698860e8c6SPeter Grehan 	DEVMETHOD(device_attach,        ata_iobus_attach),
708860e8c6SPeter Grehan 	DEVMETHOD(device_shutdown,      bus_generic_shutdown),
718860e8c6SPeter Grehan 	DEVMETHOD(device_suspend,       bus_generic_suspend),
728860e8c6SPeter Grehan 	DEVMETHOD(device_resume,        bus_generic_resume),
738860e8c6SPeter Grehan 
748860e8c6SPeter Grehan 	/* Bus methods */
758860e8c6SPeter Grehan 	DEVMETHOD(bus_print_child,          ata_iobus_print_child),
768860e8c6SPeter Grehan 	DEVMETHOD(bus_alloc_resource,       ata_iobus_alloc_resource),
778860e8c6SPeter Grehan 	DEVMETHOD(bus_release_resource,     ata_iobus_release_resource),
788860e8c6SPeter Grehan 	DEVMETHOD(bus_activate_resource,    bus_generic_activate_resource),
798860e8c6SPeter Grehan 	DEVMETHOD(bus_deactivate_resource,  bus_generic_deactivate_resource),
808860e8c6SPeter Grehan 	DEVMETHOD(bus_setup_intr,           bus_generic_setup_intr),
818860e8c6SPeter Grehan 	DEVMETHOD(bus_teardown_intr,        bus_generic_teardown_intr),
828860e8c6SPeter Grehan 
83d2ce15bdSMarius Strobl 	DEVMETHOD_END
848860e8c6SPeter Grehan };
858860e8c6SPeter Grehan 
868860e8c6SPeter Grehan static driver_t ata_iobus_driver = {
878860e8c6SPeter Grehan 	"ataiobus",
888860e8c6SPeter Grehan 	ata_iobus_methods,
898860e8c6SPeter Grehan 	0,
908860e8c6SPeter Grehan };
918860e8c6SPeter Grehan 
92f92448c9SJohn Baldwin DRIVER_MODULE(ataiobus, iobus, ata_iobus_driver, NULL, NULL);
9305a016a3SPeter Grehan MODULE_DEPEND(ata, ata, 1, 1, 1);
948860e8c6SPeter Grehan 
958860e8c6SPeter Grehan static int
968860e8c6SPeter Grehan ata_iobus_probe(device_t dev)
978860e8c6SPeter Grehan {
988860e8c6SPeter Grehan 	char *type = iobus_get_name(dev);
998860e8c6SPeter Grehan 
1008860e8c6SPeter Grehan 	if (strncmp(type, "ata", 3) != 0)
1018860e8c6SPeter Grehan 		return (ENXIO);
1028860e8c6SPeter Grehan 
1038860e8c6SPeter Grehan 	device_set_desc(dev, "PSIM ATA Controller");
1048860e8c6SPeter Grehan 	return (0);
1058860e8c6SPeter Grehan }
1068860e8c6SPeter Grehan 
1078860e8c6SPeter Grehan static int
1088860e8c6SPeter Grehan ata_iobus_attach(device_t dev)
1098860e8c6SPeter Grehan {
1108860e8c6SPeter Grehan 	/*
1118860e8c6SPeter Grehan 	 * Add a single child per controller. Should be able
1128860e8c6SPeter Grehan 	 * to add two
1138860e8c6SPeter Grehan 	 */
1145b56413dSWarner Losh 	device_add_child(dev, "ata", DEVICE_UNIT_ANY);
115*18250ec6SJohn Baldwin 	bus_attach_children(dev);
116*18250ec6SJohn Baldwin 	return (0);
1178860e8c6SPeter Grehan }
1188860e8c6SPeter Grehan 
1198860e8c6SPeter Grehan static int
1208860e8c6SPeter Grehan ata_iobus_print_child(device_t dev, device_t child)
1218860e8c6SPeter Grehan {
1228860e8c6SPeter Grehan 	int retval = 0;
1238860e8c6SPeter Grehan 
1248860e8c6SPeter Grehan 	retval += bus_print_child_header(dev, child);
1258860e8c6SPeter Grehan 	/* irq ? */
1268860e8c6SPeter Grehan 	retval += bus_print_child_footer(dev, child);
1278860e8c6SPeter Grehan 
1288860e8c6SPeter Grehan 	return (retval);
1298860e8c6SPeter Grehan }
1308860e8c6SPeter Grehan 
1318860e8c6SPeter Grehan struct resource *
1328860e8c6SPeter Grehan ata_iobus_alloc_resource(device_t dev, device_t child, int type, int *rid,
1332dd1bdf1SJustin Hibbits 			 rman_res_t start, rman_res_t end, rman_res_t count,
1342dd1bdf1SJustin Hibbits 			 u_int flags)
1358860e8c6SPeter Grehan {
1368860e8c6SPeter Grehan 	struct resource *res = NULL;
1378860e8c6SPeter Grehan 	int myrid;
1388860e8c6SPeter Grehan 	u_int *ofw_regs;
1398860e8c6SPeter Grehan 
1408860e8c6SPeter Grehan 	ofw_regs = iobus_get_regs(dev);
1418860e8c6SPeter Grehan 
1428860e8c6SPeter Grehan 	/*
1438860e8c6SPeter Grehan 	 * The reg array for the PSIM ata device has 6 start/size entries:
1448860e8c6SPeter Grehan 	 *  0 - unused
1458860e8c6SPeter Grehan 	 *  1/2/3 - unused
1468860e8c6SPeter Grehan 	 *  4/5/6 - primary command
1478860e8c6SPeter Grehan 	 *  7/8/9 - secondary command
1488860e8c6SPeter Grehan 	 *  10/11/12 - primary control
1498860e8c6SPeter Grehan 	 *  13/14/15 - secondary control
1508860e8c6SPeter Grehan 	 *  16/17/18 - primary/secondary dma registers, unimplemented
1518860e8c6SPeter Grehan 	 *
1528860e8c6SPeter Grehan 	 *  The resource values are calculated from these registers
1538860e8c6SPeter Grehan 	 */
1548860e8c6SPeter Grehan 	if (type == SYS_RES_IOPORT) {
1558860e8c6SPeter Grehan 		switch (*rid) {
1568860e8c6SPeter Grehan 		case ATA_IOADDR_RID:
1578860e8c6SPeter Grehan 			myrid = 0;
1588860e8c6SPeter Grehan 			start = ofw_regs[4];
1598860e8c6SPeter Grehan 			end = start + ATA_IOSIZE - 1;
1608860e8c6SPeter Grehan 			count = ATA_IOSIZE;
1618860e8c6SPeter Grehan 			res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
1628860e8c6SPeter Grehan 						 SYS_RES_MEMORY, &myrid,
1638860e8c6SPeter Grehan 						 start, end, count, flags);
1648860e8c6SPeter Grehan 			break;
1658860e8c6SPeter Grehan 
166db81b64fSSuleiman Souhlal 		case ATA_CTLADDR_RID:
1678860e8c6SPeter Grehan 			myrid = 0;
1688860e8c6SPeter Grehan 			start = ofw_regs[10];
169db81b64fSSuleiman Souhlal 			end = start + ATA_CTLIOSIZE - 1;
170db81b64fSSuleiman Souhlal 			count = ATA_CTLIOSIZE;
1718860e8c6SPeter Grehan 			res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
1728860e8c6SPeter Grehan 						 SYS_RES_MEMORY, &myrid,
1738860e8c6SPeter Grehan 						 start, end, count, flags);
1748860e8c6SPeter Grehan 			break;
1758860e8c6SPeter Grehan 
1768860e8c6SPeter Grehan 		case ATA_BMADDR_RID:
1778860e8c6SPeter Grehan 			/* DMA not properly supported by psim */
1788860e8c6SPeter Grehan 			break;
1798860e8c6SPeter Grehan 		}
1808860e8c6SPeter Grehan 		return (res);
1818860e8c6SPeter Grehan 
1828860e8c6SPeter Grehan 	} else if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) {
1838860e8c6SPeter Grehan 		/*
1848860e8c6SPeter Grehan 		 * Pass this on to the parent
1858860e8c6SPeter Grehan 		 */
1868860e8c6SPeter Grehan 		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
1878860e8c6SPeter Grehan 					   SYS_RES_IRQ, rid, 0, ~0, 1, flags));
1888860e8c6SPeter Grehan 
1898860e8c6SPeter Grehan 	} else {
1908860e8c6SPeter Grehan 		return (NULL);
1918860e8c6SPeter Grehan 	}
1928860e8c6SPeter Grehan }
1938860e8c6SPeter Grehan 
1948860e8c6SPeter Grehan static int
1959dbf5b0eSJohn Baldwin ata_iobus_release_resource(device_t dev, device_t child, struct resource *r)
1968860e8c6SPeter Grehan {
1978860e8c6SPeter Grehan 	/* no hotplug... */
1988860e8c6SPeter Grehan 	return (0);
1998860e8c6SPeter Grehan }
2008860e8c6SPeter Grehan 
2018860e8c6SPeter Grehan /*
2028860e8c6SPeter Grehan  * Define the actual ATA device. This is a sub-bus to the ata-iobus layer
2038860e8c6SPeter Grehan  * to allow the higher layer bus to massage the resource allocation.
2048860e8c6SPeter Grehan  */
2058860e8c6SPeter Grehan 
2068860e8c6SPeter Grehan static  int  ata_iobus_sub_probe(device_t dev);
207066f913aSAlexander Motin static  int  ata_iobus_sub_setmode(device_t dev, int target, int mode);
2088860e8c6SPeter Grehan 
2098860e8c6SPeter Grehan static device_method_t ata_iobus_sub_methods[] = {
2108860e8c6SPeter Grehan 	/* Device interface */
2118860e8c6SPeter Grehan 	DEVMETHOD(device_probe,     ata_iobus_sub_probe),
2128860e8c6SPeter Grehan 	DEVMETHOD(device_attach,    ata_attach),
2138860e8c6SPeter Grehan 	DEVMETHOD(device_detach,    ata_detach),
2148860e8c6SPeter Grehan 	DEVMETHOD(device_resume,    ata_resume),
2158860e8c6SPeter Grehan 
21698cbfce5SPeter Grehan 	/* ATA interface */
21798cbfce5SPeter Grehan 	DEVMETHOD(ata_setmode,	    ata_iobus_sub_setmode),
218d2ce15bdSMarius Strobl 	DEVMETHOD_END
2198860e8c6SPeter Grehan };
2208860e8c6SPeter Grehan 
2218860e8c6SPeter Grehan static driver_t ata_iobus_sub_driver = {
2228860e8c6SPeter Grehan 	"ata",
2238860e8c6SPeter Grehan 	ata_iobus_sub_methods,
2248860e8c6SPeter Grehan 	sizeof(struct ata_channel),
2258860e8c6SPeter Grehan };
2268860e8c6SPeter Grehan 
227d5a7306cSJohn Baldwin DRIVER_MODULE(ata, ataiobus, ata_iobus_sub_driver, NULL, NULL);
2288860e8c6SPeter Grehan 
229c10763d4SPeter Grehan static int
2308860e8c6SPeter Grehan ata_iobus_sub_probe(device_t dev)
2318860e8c6SPeter Grehan {
2328860e8c6SPeter Grehan 	struct ata_channel *ch = device_get_softc(dev);
2338860e8c6SPeter Grehan 
2348860e8c6SPeter Grehan 	/* Only a single unit per controller thus far */
2358860e8c6SPeter Grehan 	ch->unit = 0;
2368a7f8971SPeter Grehan 	ch->flags = (ATA_USE_16BIT|ATA_NO_SLAVE);
237c00f3b9dSPeter Grehan 	ata_generic_hw(dev);
2388860e8c6SPeter Grehan 
2398860e8c6SPeter Grehan 	return ata_probe(dev);
2408860e8c6SPeter Grehan }
24198cbfce5SPeter Grehan 
242066f913aSAlexander Motin static int
243edbb0904SNathan Whitehorn ata_iobus_sub_setmode(device_t parent, int target, int mode)
24498cbfce5SPeter Grehan {
24598cbfce5SPeter Grehan 	/* Only ever PIO mode here... */
246066f913aSAlexander Motin 	return (ATA_PIO);
24798cbfce5SPeter Grehan }
248