19d292ea1SAdrian Chadd /*-
29d292ea1SAdrian Chadd * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
38e35bf83SLandon J. Fuller * Copyright (c) 2017 The FreeBSD Foundation
49d292ea1SAdrian Chadd * All rights reserved.
59d292ea1SAdrian Chadd *
68e35bf83SLandon J. Fuller * Portions of this software were developed by Landon Fuller
78e35bf83SLandon J. Fuller * under sponsorship from the FreeBSD Foundation.
88e35bf83SLandon J. Fuller *
99d292ea1SAdrian Chadd * Redistribution and use in source and binary forms, with or without
109d292ea1SAdrian Chadd * modification, are permitted provided that the following conditions
119d292ea1SAdrian Chadd * are met:
129d292ea1SAdrian Chadd * 1. Redistributions of source code must retain the above copyright
139d292ea1SAdrian Chadd * notice, this list of conditions and the following disclaimer,
149d292ea1SAdrian Chadd * without modification.
159d292ea1SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer
169d292ea1SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
179d292ea1SAdrian Chadd * redistribution must be conditioned upon including a substantially
189d292ea1SAdrian Chadd * similar Disclaimer requirement for further binary redistribution.
199d292ea1SAdrian Chadd *
209d292ea1SAdrian Chadd * NO WARRANTY
219d292ea1SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
229d292ea1SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
239d292ea1SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
249d292ea1SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
259d292ea1SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
269d292ea1SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
279d292ea1SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
289d292ea1SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
299d292ea1SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
309d292ea1SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
319d292ea1SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES.
329d292ea1SAdrian Chadd */
339d292ea1SAdrian Chadd
349d292ea1SAdrian Chadd #include <sys/param.h>
359d292ea1SAdrian Chadd #include <sys/kernel.h>
369d292ea1SAdrian Chadd #include <sys/bus.h>
379d292ea1SAdrian Chadd #include <sys/module.h>
389d292ea1SAdrian Chadd
399d292ea1SAdrian Chadd #include <dev/bhnd/bhnd_ids.h>
409d292ea1SAdrian Chadd #include <dev/bhnd/bhnd.h>
419d292ea1SAdrian Chadd
42*4e96bf3aSLandon J. Fuller #include "bhnd_pwrctl_hostb_if.h"
43*4e96bf3aSLandon J. Fuller
449d292ea1SAdrian Chadd #include "bhndbvar.h"
459d292ea1SAdrian Chadd
469d292ea1SAdrian Chadd /*
479d292ea1SAdrian Chadd * bhnd(4) driver mix-in providing a shared common methods for
489d292ea1SAdrian Chadd * bhnd devices attached via a bhndb bridge.
499d292ea1SAdrian Chadd */
509d292ea1SAdrian Chadd
519d292ea1SAdrian Chadd static int
bhnd_bhndb_read_board_info(device_t dev,device_t child,struct bhnd_board_info * info)529d292ea1SAdrian Chadd bhnd_bhndb_read_board_info(device_t dev, device_t child,
539d292ea1SAdrian Chadd struct bhnd_board_info *info)
549d292ea1SAdrian Chadd {
559d292ea1SAdrian Chadd int error;
569d292ea1SAdrian Chadd
579d292ea1SAdrian Chadd /* Initialize with NVRAM-derived values */
589d292ea1SAdrian Chadd if ((error = bhnd_bus_generic_read_board_info(dev, child, info)))
599d292ea1SAdrian Chadd return (error);
609d292ea1SAdrian Chadd
619d292ea1SAdrian Chadd /* Let the bridge fill in any additional data */
629d292ea1SAdrian Chadd return (BHNDB_POPULATE_BOARD_INFO(device_get_parent(dev), dev, info));
639d292ea1SAdrian Chadd }
649d292ea1SAdrian Chadd
659d292ea1SAdrian Chadd static bhnd_attach_type
bhnd_bhndb_get_attach_type(device_t dev,device_t child)669d292ea1SAdrian Chadd bhnd_bhndb_get_attach_type(device_t dev, device_t child)
679d292ea1SAdrian Chadd {
689d292ea1SAdrian Chadd /* It's safe to assume that a bridged device is always an adapter */
699d292ea1SAdrian Chadd return (BHND_ATTACH_ADAPTER);
709d292ea1SAdrian Chadd }
719d292ea1SAdrian Chadd
7263fb0e82SLandon J. Fuller static bool
bhnd_bhndb_is_hw_disabled(device_t dev,device_t child)7363fb0e82SLandon J. Fuller bhnd_bhndb_is_hw_disabled(device_t dev, device_t child)
7463fb0e82SLandon J. Fuller {
7563fb0e82SLandon J. Fuller struct bhnd_core_info core = bhnd_get_core_info(child);
7663fb0e82SLandon J. Fuller
7763fb0e82SLandon J. Fuller /* Delegate to parent bridge */
7863fb0e82SLandon J. Fuller return (BHNDB_IS_CORE_DISABLED(device_get_parent(dev), dev, &core));
7963fb0e82SLandon J. Fuller }
8063fb0e82SLandon J. Fuller
81111d7cb2SLandon J. Fuller static device_t
bhnd_bhndb_find_hostb_device(device_t dev)82111d7cb2SLandon J. Fuller bhnd_bhndb_find_hostb_device(device_t dev)
83111d7cb2SLandon J. Fuller {
84111d7cb2SLandon J. Fuller struct bhnd_core_info core;
85111d7cb2SLandon J. Fuller struct bhnd_core_match md;
86111d7cb2SLandon J. Fuller int error;
87111d7cb2SLandon J. Fuller
88111d7cb2SLandon J. Fuller /* Ask the bridge for the hostb core info */
89111d7cb2SLandon J. Fuller if ((error = BHNDB_GET_HOSTB_CORE(device_get_parent(dev), dev, &core)))
90111d7cb2SLandon J. Fuller return (NULL);
91111d7cb2SLandon J. Fuller
92111d7cb2SLandon J. Fuller /* Find the corresponding bus device */
93111d7cb2SLandon J. Fuller md = bhnd_core_get_match_desc(&core);
948e35bf83SLandon J. Fuller return (bhnd_bus_match_child(dev, &md));
95111d7cb2SLandon J. Fuller }
96111d7cb2SLandon J. Fuller
97824b48efSLandon J. Fuller static int
bhnd_bhndb_map_intr(device_t dev,device_t child,u_int intr,rman_res_t * irq)98caeff9a3SLandon J. Fuller bhnd_bhndb_map_intr(device_t dev, device_t child, u_int intr, rman_res_t *irq)
99824b48efSLandon J. Fuller {
100824b48efSLandon J. Fuller /* Delegate to parent bridge */
101caeff9a3SLandon J. Fuller return (BHND_BUS_MAP_INTR(device_get_parent(dev), child, intr, irq));
102caeff9a3SLandon J. Fuller }
103caeff9a3SLandon J. Fuller
104caeff9a3SLandon J. Fuller static void
bhnd_bhndb_unmap_intr(device_t dev,device_t child,rman_res_t irq)105caeff9a3SLandon J. Fuller bhnd_bhndb_unmap_intr(device_t dev, device_t child, rman_res_t irq)
106caeff9a3SLandon J. Fuller {
107caeff9a3SLandon J. Fuller /* Delegate to parent bridge */
108caeff9a3SLandon J. Fuller return (BHND_BUS_UNMAP_INTR(device_get_parent(dev), child, irq));
109824b48efSLandon J. Fuller }
110824b48efSLandon J. Fuller
111f90f4b65SLandon J. Fuller static bhnd_clksrc
bhnd_bhndb_pwrctl_get_clksrc(device_t dev,device_t child,bhnd_clock clock)112f90f4b65SLandon J. Fuller bhnd_bhndb_pwrctl_get_clksrc(device_t dev, device_t child,
113f90f4b65SLandon J. Fuller bhnd_clock clock)
114f90f4b65SLandon J. Fuller {
115f90f4b65SLandon J. Fuller /* Delegate to parent bridge */
116*4e96bf3aSLandon J. Fuller return (BHND_PWRCTL_HOSTB_GET_CLKSRC(device_get_parent(dev), child,
117f90f4b65SLandon J. Fuller clock));
118f90f4b65SLandon J. Fuller }
119f90f4b65SLandon J. Fuller
120f90f4b65SLandon J. Fuller static int
bhnd_bhndb_pwrctl_gate_clock(device_t dev,device_t child,bhnd_clock clock)121f90f4b65SLandon J. Fuller bhnd_bhndb_pwrctl_gate_clock(device_t dev, device_t child,
122f90f4b65SLandon J. Fuller bhnd_clock clock)
123f90f4b65SLandon J. Fuller {
124f90f4b65SLandon J. Fuller /* Delegate to parent bridge */
125*4e96bf3aSLandon J. Fuller return (BHND_PWRCTL_HOSTB_GATE_CLOCK(device_get_parent(dev), child,
126f90f4b65SLandon J. Fuller clock));
127f90f4b65SLandon J. Fuller }
128f90f4b65SLandon J. Fuller
129f90f4b65SLandon J. Fuller static int
bhnd_bhndb_pwrctl_ungate_clock(device_t dev,device_t child,bhnd_clock clock)130f90f4b65SLandon J. Fuller bhnd_bhndb_pwrctl_ungate_clock(device_t dev, device_t child,
131f90f4b65SLandon J. Fuller bhnd_clock clock)
132f90f4b65SLandon J. Fuller {
133f90f4b65SLandon J. Fuller /* Delegate to parent bridge */
134*4e96bf3aSLandon J. Fuller return (BHND_PWRCTL_HOSTB_UNGATE_CLOCK(device_get_parent(dev), child,
135f90f4b65SLandon J. Fuller clock));
136f90f4b65SLandon J. Fuller }
137f90f4b65SLandon J. Fuller
138caeff9a3SLandon J. Fuller static int
bhnd_bhndb_setup_intr(device_t dev,device_t child,struct resource * irq,int flags,driver_filter_t * filter,driver_intr_t * intr,void * arg,void ** cookiep)139caeff9a3SLandon J. Fuller bhnd_bhndb_setup_intr(device_t dev, device_t child, struct resource *irq,
140caeff9a3SLandon J. Fuller int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
141caeff9a3SLandon J. Fuller void **cookiep)
142caeff9a3SLandon J. Fuller {
143caeff9a3SLandon J. Fuller device_t core, bus;
144caeff9a3SLandon J. Fuller int error;
145caeff9a3SLandon J. Fuller
146caeff9a3SLandon J. Fuller /* Find the actual bus-attached child core */
147caeff9a3SLandon J. Fuller core = child;
148caeff9a3SLandon J. Fuller while ((bus = device_get_parent(core)) != NULL) {
149caeff9a3SLandon J. Fuller if (bus == dev)
150caeff9a3SLandon J. Fuller break;
151caeff9a3SLandon J. Fuller
152caeff9a3SLandon J. Fuller core = bus;
153caeff9a3SLandon J. Fuller }
154caeff9a3SLandon J. Fuller
155caeff9a3SLandon J. Fuller KASSERT(core != NULL, ("%s is not a child of %s",
156caeff9a3SLandon J. Fuller device_get_nameunit(child), device_get_nameunit(dev)));
157caeff9a3SLandon J. Fuller
158caeff9a3SLandon J. Fuller /* Ask our bridge to enable interrupt routing for the child core */
159caeff9a3SLandon J. Fuller error = BHNDB_ROUTE_INTERRUPTS(device_get_parent(dev), core);
160caeff9a3SLandon J. Fuller if (error)
161caeff9a3SLandon J. Fuller return (error);
162caeff9a3SLandon J. Fuller
163caeff9a3SLandon J. Fuller /* Delegate actual interrupt setup to the default bhnd bus
164caeff9a3SLandon J. Fuller * implementation */
165caeff9a3SLandon J. Fuller return (bhnd_generic_setup_intr(dev, child, irq, flags, filter, intr,
166caeff9a3SLandon J. Fuller arg, cookiep));
167caeff9a3SLandon J. Fuller }
168caeff9a3SLandon J. Fuller
1699d292ea1SAdrian Chadd static device_method_t bhnd_bhndb_methods[] = {
170caeff9a3SLandon J. Fuller /* Bus interface */
171caeff9a3SLandon J. Fuller DEVMETHOD(bus_setup_intr, bhnd_bhndb_setup_intr),
172caeff9a3SLandon J. Fuller
1739d292ea1SAdrian Chadd /* BHND interface */
1749d292ea1SAdrian Chadd DEVMETHOD(bhnd_bus_get_attach_type, bhnd_bhndb_get_attach_type),
17563fb0e82SLandon J. Fuller DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bhndb_is_hw_disabled),
176111d7cb2SLandon J. Fuller DEVMETHOD(bhnd_bus_find_hostb_device, bhnd_bhndb_find_hostb_device),
1779d292ea1SAdrian Chadd DEVMETHOD(bhnd_bus_read_board_info, bhnd_bhndb_read_board_info),
178caeff9a3SLandon J. Fuller DEVMETHOD(bhnd_bus_map_intr, bhnd_bhndb_map_intr),
179caeff9a3SLandon J. Fuller DEVMETHOD(bhnd_bus_unmap_intr, bhnd_bhndb_unmap_intr),
1809d292ea1SAdrian Chadd
181*4e96bf3aSLandon J. Fuller /* BHND PWRCTL hostb interface */
182*4e96bf3aSLandon J. Fuller DEVMETHOD(bhnd_pwrctl_hostb_get_clksrc, bhnd_bhndb_pwrctl_get_clksrc),
183*4e96bf3aSLandon J. Fuller DEVMETHOD(bhnd_pwrctl_hostb_gate_clock, bhnd_bhndb_pwrctl_gate_clock),
184*4e96bf3aSLandon J. Fuller DEVMETHOD(bhnd_pwrctl_hostb_ungate_clock, bhnd_bhndb_pwrctl_ungate_clock),
185f90f4b65SLandon J. Fuller
1869d292ea1SAdrian Chadd DEVMETHOD_END
1879d292ea1SAdrian Chadd };
1889d292ea1SAdrian Chadd
1899d292ea1SAdrian Chadd DEFINE_CLASS_0(bhnd, bhnd_bhndb_driver, bhnd_bhndb_methods, 0);
190