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