1/*-
2 * Copyright (c) 2009-2012 Alexander Motin <mav@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include "opt_acpi.h"
31#include "opt_platform.h"
32
33#include <sys/param.h>
34#include <sys/module.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/bus.h>
38#include <sys/conf.h>
39#include <sys/endian.h>
40#include <sys/malloc.h>
41#include <sys/lock.h>
42#include <sys/mutex.h>
43#include <sys/rman.h>
44
45#include <machine/bus.h>
46#include <machine/resource.h>
47
48#include <dev/ahci/ahci.h>
49
50#ifdef DEV_ACPI
51#include <contrib/dev/acpica/include/acpi.h>
52#include <dev/acpica/acpivar.h>
53
54#include <dev/pci/pcivar.h>
55#include <dev/pci/pcireg.h>
56#endif
57
58#ifdef FDT
59#include <dev/ofw/ofw_bus.h>
60#include <dev/ofw/ofw_bus_subr.h>
61
62static struct ofw_compat_data compat_data[] = {
63	{"generic-ahci", 		1},
64	{"snps,dwc-ahci",		1},
65	{"marvell,armada-3700-ahci",	1},
66	{NULL,				0}
67};
68
69static int
70ahci_fdt_probe(device_t dev)
71{
72	struct ahci_controller *ctlr = device_get_softc(dev);
73	phandle_t node;
74
75	if (!ofw_bus_status_okay(dev))
76		return (ENXIO);
77
78	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
79		return (ENXIO);
80
81	device_set_desc_copy(dev, "AHCI SATA controller");
82	node = ofw_bus_get_node(dev);
83	ctlr->dma_coherent = OF_hasprop(node, "dma-coherent");
84	return (BUS_PROBE_DEFAULT);
85}
86#endif
87
88#ifdef DEV_ACPI
89static int
90ahci_acpi_probe(device_t dev)
91{
92	struct ahci_controller *ctlr = device_get_softc(dev);
93	ACPI_HANDLE h;
94
95	if ((h = acpi_get_handle(dev)) == NULL)
96		return (ENXIO);
97
98	if (pci_get_class(dev) == PCIC_STORAGE &&
99	    pci_get_subclass(dev) == PCIS_STORAGE_SATA &&
100	    pci_get_progif(dev) == PCIP_STORAGE_SATA_AHCI_1_0) {
101		device_set_desc_copy(dev, "AHCI SATA controller");
102		if (ACPI_FAILURE(acpi_GetInteger(h, "_CCA",
103		      &ctlr->dma_coherent)))
104			ctlr->dma_coherent = 0;
105		if (bootverbose)
106			device_printf(dev, "Bus is%s cache-coherent\n",
107			  ctlr->dma_coherent ? "" : " not");
108		return (BUS_PROBE_DEFAULT);
109	}
110
111	return (ENXIO);
112}
113#endif
114
115static int
116ahci_gen_ctlr_reset(device_t dev)
117{
118
119	return ahci_ctlr_reset(dev);
120}
121
122static int
123ahci_gen_attach(device_t dev)
124{
125	struct ahci_controller *ctlr = device_get_softc(dev);
126	int	error;
127
128	ctlr->r_rid = 0;
129	ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ctlr->r_rid,
130	    RF_ACTIVE);
131	if (ctlr->r_mem == NULL)
132		return (ENXIO);
133
134	/* Setup controller defaults. */
135	ctlr->numirqs = 1;
136
137	/* Reset controller */
138	if ((error = ahci_gen_ctlr_reset(dev)) == 0)
139		error = ahci_attach(dev);
140
141	if (error != 0) {
142		if (ctlr->r_mem != NULL)
143			bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid,
144			    ctlr->r_mem);
145	}
146	return error;
147}
148
149static int
150ahci_gen_detach(device_t dev)
151{
152
153	ahci_detach(dev);
154	return (0);
155}
156
157#ifdef FDT
158static devclass_t ahci_gen_fdt_devclass;
159static device_method_t ahci_fdt_methods[] = {
160	DEVMETHOD(device_probe,     ahci_fdt_probe),
161	DEVMETHOD(device_attach,    ahci_gen_attach),
162	DEVMETHOD(device_detach,    ahci_gen_detach),
163	DEVMETHOD(bus_print_child,  ahci_print_child),
164	DEVMETHOD(bus_alloc_resource,       ahci_alloc_resource),
165	DEVMETHOD(bus_release_resource,     ahci_release_resource),
166	DEVMETHOD(bus_setup_intr,   ahci_setup_intr),
167	DEVMETHOD(bus_teardown_intr,ahci_teardown_intr),
168	DEVMETHOD(bus_child_location_str, ahci_child_location_str),
169	DEVMETHOD(bus_get_dma_tag,  ahci_get_dma_tag),
170	DEVMETHOD_END
171};
172static driver_t ahci_fdt_driver = {
173	"ahci",
174	ahci_fdt_methods,
175	sizeof(struct ahci_controller)
176};
177DRIVER_MODULE(ahci_fdt, simplebus, ahci_fdt_driver, ahci_gen_fdt_devclass,
178    NULL, NULL);
179#endif
180
181#ifdef DEV_ACPI
182static devclass_t ahci_gen_acpi_devclass;
183static device_method_t ahci_acpi_methods[] = {
184	DEVMETHOD(device_probe,     ahci_acpi_probe),
185	DEVMETHOD(device_attach,    ahci_gen_attach),
186	DEVMETHOD(device_detach,    ahci_gen_detach),
187	DEVMETHOD(bus_print_child,  ahci_print_child),
188	DEVMETHOD(bus_alloc_resource,       ahci_alloc_resource),
189	DEVMETHOD(bus_release_resource,     ahci_release_resource),
190	DEVMETHOD(bus_setup_intr,   ahci_setup_intr),
191	DEVMETHOD(bus_teardown_intr,ahci_teardown_intr),
192	DEVMETHOD(bus_child_location_str, ahci_child_location_str),
193	DEVMETHOD(bus_get_dma_tag,  ahci_get_dma_tag),
194	DEVMETHOD_END
195};
196static driver_t ahci_acpi_driver = {
197	"ahci",
198	ahci_acpi_methods,
199	sizeof(struct ahci_controller)
200};
201DRIVER_MODULE(ahci_acpi, acpi, ahci_acpi_driver, ahci_gen_acpi_devclass,
202    NULL, NULL);
203#endif
204