1139825Simp/*- 2103620Sgrehan * Copyright 2002 by Peter Grehan. All rights reserved. 3103620Sgrehan * 4103620Sgrehan * Redistribution and use in source and binary forms, with or without 5103620Sgrehan * modification, are permitted provided that the following conditions 6103620Sgrehan * are met: 7103620Sgrehan * 1. Redistributions of source code must retain the above copyright 8103620Sgrehan * notice, this list of conditions and the following disclaimer. 9103620Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 10103620Sgrehan * notice, this list of conditions and the following disclaimer in the 11103620Sgrehan * documentation and/or other materials provided with the distribution. 12103620Sgrehan * 3. The name of the author may not be used to endorse or promote products 13103620Sgrehan * derived from this software without specific prior written permission. 14103620Sgrehan * 15103620Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16103620Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17103620Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18103620Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19103620Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20103620Sgrehan * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21103620Sgrehan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22103620Sgrehan * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23103620Sgrehan * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24103620Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25103620Sgrehan * SUCH DAMAGE. 26103620Sgrehan */ 27103620Sgrehan 28249213Smarius#include <sys/cdefs.h> 29249213Smarius__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/psim/ata_iobus.c 249213 2013-04-06 19:12:49Z marius $"); 30249213Smarius 31103620Sgrehan/* 32103620Sgrehan * PSIM local bus ATA controller 33103620Sgrehan */ 34103620Sgrehan#include <sys/param.h> 35103620Sgrehan#include <sys/systm.h> 36103620Sgrehan#include <sys/kernel.h> 37103620Sgrehan#include <sys/module.h> 38103620Sgrehan#include <sys/bus.h> 39103620Sgrehan#include <sys/malloc.h> 40124466Sgrehan#include <sys/sema.h> 41120335Sgrehan#include <sys/taskqueue.h> 42103620Sgrehan#include <machine/stdarg.h> 43124581Sgrehan#include <vm/uma.h> 44103620Sgrehan#include <machine/resource.h> 45103620Sgrehan#include <machine/bus.h> 46103620Sgrehan#include <sys/rman.h> 47111404Sgrehan#include <sys/ata.h> 48103620Sgrehan#include <dev/ata/ata-all.h> 49144457Sgrehan#include <ata_if.h> 50103620Sgrehan 51103620Sgrehan#include <dev/ofw/openfirm.h> 52103620Sgrehan#include <powerpc/psim/iobusvar.h> 53103620Sgrehan 54103620Sgrehan/* 55103620Sgrehan * Define the iobus ata bus attachment. This creates a pseudo-bus that 56103620Sgrehan * the ATA device can be attached to 57103620Sgrehan */ 58103620Sgrehanstatic int ata_iobus_attach(device_t dev); 59103620Sgrehanstatic int ata_iobus_probe(device_t dev); 60103620Sgrehanstatic int ata_iobus_print_child(device_t dev, device_t child); 61103620Sgrehanstruct resource *ata_iobus_alloc_resource(device_t, device_t, int, int *, 62103620Sgrehan u_long, u_long, u_long, u_int); 63103620Sgrehanstatic int ata_iobus_release_resource(device_t, device_t, int, int, 64103620Sgrehan struct resource *); 65103620Sgrehan 66103620Sgrehanstatic device_method_t ata_iobus_methods[] = { 67103620Sgrehan /* Device interface */ 68103620Sgrehan DEVMETHOD(device_probe, ata_iobus_probe), 69103620Sgrehan DEVMETHOD(device_attach, ata_iobus_attach), 70103620Sgrehan DEVMETHOD(device_shutdown, bus_generic_shutdown), 71103620Sgrehan DEVMETHOD(device_suspend, bus_generic_suspend), 72103620Sgrehan DEVMETHOD(device_resume, bus_generic_resume), 73103620Sgrehan 74103620Sgrehan /* Bus methods */ 75103620Sgrehan DEVMETHOD(bus_print_child, ata_iobus_print_child), 76103620Sgrehan DEVMETHOD(bus_alloc_resource, ata_iobus_alloc_resource), 77103620Sgrehan DEVMETHOD(bus_release_resource, ata_iobus_release_resource), 78103620Sgrehan DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 79103620Sgrehan DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 80103620Sgrehan DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 81103620Sgrehan DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 82103620Sgrehan 83249213Smarius DEVMETHOD_END 84103620Sgrehan}; 85103620Sgrehan 86103620Sgrehanstatic driver_t ata_iobus_driver = { 87103620Sgrehan "ataiobus", 88103620Sgrehan ata_iobus_methods, 89103620Sgrehan 0, 90103620Sgrehan}; 91103620Sgrehan 92103620Sgrehanstatic devclass_t ata_iobus_devclass; 93103620Sgrehan 94249213SmariusDRIVER_MODULE(ataiobus, iobus, ata_iobus_driver, ata_iobus_devclass, NULL, 95249213Smarius NULL); 96144359SgrehanMODULE_DEPEND(ata, ata, 1, 1, 1); 97103620Sgrehan 98103620Sgrehanstatic int 99103620Sgrehanata_iobus_probe(device_t dev) 100103620Sgrehan{ 101103620Sgrehan char *type = iobus_get_name(dev); 102103620Sgrehan 103103620Sgrehan if (strncmp(type, "ata", 3) != 0) 104103620Sgrehan return (ENXIO); 105103620Sgrehan 106103620Sgrehan device_set_desc(dev, "PSIM ATA Controller"); 107125690Sgrehan return (0); 108103620Sgrehan} 109103620Sgrehan 110103620Sgrehan 111103620Sgrehanstatic int 112103620Sgrehanata_iobus_attach(device_t dev) 113103620Sgrehan{ 114103620Sgrehan /* 115103620Sgrehan * Add a single child per controller. Should be able 116103620Sgrehan * to add two 117103620Sgrehan */ 118193935Simp device_add_child(dev, "ata", -1); 119103620Sgrehan return (bus_generic_attach(dev)); 120103620Sgrehan} 121103620Sgrehan 122103620Sgrehan 123103620Sgrehanstatic int 124103620Sgrehanata_iobus_print_child(device_t dev, device_t child) 125103620Sgrehan{ 126125690Sgrehan int retval = 0; 127103620Sgrehan 128125690Sgrehan retval += bus_print_child_header(dev, child); 129125690Sgrehan /* irq ? */ 130125690Sgrehan retval += bus_print_child_footer(dev, child); 131103620Sgrehan 132125690Sgrehan return (retval); 133103620Sgrehan} 134103620Sgrehan 135103620Sgrehan 136103620Sgrehanstruct resource * 137103620Sgrehanata_iobus_alloc_resource(device_t dev, device_t child, int type, int *rid, 138103620Sgrehan u_long start, u_long end, u_long count, u_int flags) 139103620Sgrehan{ 140103620Sgrehan struct resource *res = NULL; 141103620Sgrehan int myrid; 142103620Sgrehan u_int *ofw_regs; 143103620Sgrehan 144103620Sgrehan ofw_regs = iobus_get_regs(dev); 145103620Sgrehan 146103620Sgrehan /* 147103620Sgrehan * The reg array for the PSIM ata device has 6 start/size entries: 148103620Sgrehan * 0 - unused 149103620Sgrehan * 1/2/3 - unused 150103620Sgrehan * 4/5/6 - primary command 151103620Sgrehan * 7/8/9 - secondary command 152103620Sgrehan * 10/11/12 - primary control 153103620Sgrehan * 13/14/15 - secondary control 154103620Sgrehan * 16/17/18 - primary/secondary dma registers, unimplemented 155103620Sgrehan * 156103620Sgrehan * The resource values are calculated from these registers 157103620Sgrehan */ 158103620Sgrehan if (type == SYS_RES_IOPORT) { 159103620Sgrehan switch (*rid) { 160103620Sgrehan case ATA_IOADDR_RID: 161103620Sgrehan myrid = 0; 162103620Sgrehan start = ofw_regs[4]; 163103620Sgrehan end = start + ATA_IOSIZE - 1; 164103620Sgrehan count = ATA_IOSIZE; 165103620Sgrehan res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 166103620Sgrehan SYS_RES_MEMORY, &myrid, 167103620Sgrehan start, end, count, flags); 168103620Sgrehan break; 169103620Sgrehan 170144956Sssouhlal case ATA_CTLADDR_RID: 171103620Sgrehan myrid = 0; 172103620Sgrehan start = ofw_regs[10]; 173144956Sssouhlal end = start + ATA_CTLIOSIZE - 1; 174144956Sssouhlal count = ATA_CTLIOSIZE; 175103620Sgrehan res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 176103620Sgrehan SYS_RES_MEMORY, &myrid, 177103620Sgrehan start, end, count, flags); 178103620Sgrehan break; 179103620Sgrehan 180103620Sgrehan case ATA_BMADDR_RID: 181103620Sgrehan /* DMA not properly supported by psim */ 182103620Sgrehan break; 183103620Sgrehan } 184103620Sgrehan return (res); 185103620Sgrehan 186103620Sgrehan } else if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) { 187103620Sgrehan /* 188103620Sgrehan * Pass this on to the parent 189103620Sgrehan */ 190103620Sgrehan return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 191103620Sgrehan SYS_RES_IRQ, rid, 0, ~0, 1, flags)); 192103620Sgrehan 193125690Sgrehan } else { 194103620Sgrehan return (NULL); 195103620Sgrehan } 196103620Sgrehan} 197103620Sgrehan 198103620Sgrehan 199103620Sgrehanstatic int 200103620Sgrehanata_iobus_release_resource(device_t dev, device_t child, int type, int rid, 201103620Sgrehan struct resource *r) 202103620Sgrehan{ 203103620Sgrehan /* no hotplug... */ 204103620Sgrehan return (0); 205103620Sgrehan} 206103620Sgrehan 207103620Sgrehan 208103620Sgrehan/* 209103620Sgrehan * Define the actual ATA device. This is a sub-bus to the ata-iobus layer 210103620Sgrehan * to allow the higher layer bus to massage the resource allocation. 211103620Sgrehan */ 212103620Sgrehan 213103620Sgrehanstatic int ata_iobus_sub_probe(device_t dev); 214200171Smavstatic int ata_iobus_sub_setmode(device_t dev, int target, int mode); 215103620Sgrehan 216103620Sgrehanstatic device_method_t ata_iobus_sub_methods[] = { 217103620Sgrehan /* Device interface */ 218103620Sgrehan DEVMETHOD(device_probe, ata_iobus_sub_probe), 219103620Sgrehan DEVMETHOD(device_attach, ata_attach), 220103620Sgrehan DEVMETHOD(device_detach, ata_detach), 221103620Sgrehan DEVMETHOD(device_resume, ata_resume), 222125690Sgrehan 223144457Sgrehan /* ATA interface */ 224144457Sgrehan DEVMETHOD(ata_setmode, ata_iobus_sub_setmode), 225249213Smarius DEVMETHOD_END 226103620Sgrehan}; 227103620Sgrehan 228103620Sgrehanstatic driver_t ata_iobus_sub_driver = { 229103620Sgrehan "ata", 230103620Sgrehan ata_iobus_sub_methods, 231103620Sgrehan sizeof(struct ata_channel), 232103620Sgrehan}; 233103620Sgrehan 234249213SmariusDRIVER_MODULE(ata, ataiobus, ata_iobus_sub_driver, ata_devclass, NULL, NULL); 235103620Sgrehan 236143632Sgrehanstatic int 237103620Sgrehanata_iobus_sub_probe(device_t dev) 238103620Sgrehan{ 239103620Sgrehan struct ata_channel *ch = device_get_softc(dev); 240103620Sgrehan 241103620Sgrehan /* Only a single unit per controller thus far */ 242103620Sgrehan ch->unit = 0; 243109483Sgrehan ch->flags = (ATA_USE_16BIT|ATA_NO_SLAVE); 244152305Sgrehan ata_generic_hw(dev); 245103620Sgrehan 246103620Sgrehan return ata_probe(dev); 247103620Sgrehan} 248144457Sgrehan 249200171Smavstatic int 250200182Snwhitehornata_iobus_sub_setmode(device_t parent, int target, int mode) 251144457Sgrehan{ 252144457Sgrehan /* Only ever PIO mode here... */ 253200171Smav return (ATA_PIO); 254144457Sgrehan} 255