1/*- 2 * Copyright (c) 2004 Jason L. Wright (jason@thought.net) 3 * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 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 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 * 27 * from: OpenBSD: clkbrd.c,v 1.5 2004/10/01 18:18:49 jason Exp 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: releng/10.3/sys/sparc64/fhc/clkbrd.c 157225 2006-03-28 19:46:48Z marius $"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/kernel.h> 36#include <sys/module.h> 37#include <sys/resource.h> 38#include <sys/rman.h> 39 40#include <dev/led/led.h> 41#include <dev/ofw/ofw_bus.h> 42 43#include <machine/bus.h> 44#include <machine/resource.h> 45 46#include <sparc64/fhc/clkbrdreg.h> 47 48#define CLKBRD_NREG 3 49 50#define CLKBRD_CF 0 51#define CLKBRD_CLK 1 52#define CLKBRD_CLKVER 2 53 54struct clkbrd_softc { 55 struct device *sc_dev; 56 struct resource *sc_res[CLKBRD_NREG]; 57 int sc_rid[CLKBRD_NREG]; 58 bus_space_tag_t sc_bt[CLKBRD_NREG]; 59 bus_space_handle_t sc_bh[CLKBRD_NREG]; 60 uint8_t sc_clk_ctrl; 61 struct cdev *sc_led_dev; 62 int sc_flags; 63#define CLKBRD_HAS_CLKVER (1 << 0) 64}; 65 66static devclass_t clkbrd_devclass; 67 68static device_probe_t clkbrd_probe; 69static device_attach_t clkbrd_attach; 70static device_detach_t clkbrd_detach; 71 72static void clkbrd_free_resources(struct clkbrd_softc *); 73static void clkbrd_led_func(void *, int); 74 75static device_method_t clkbrd_methods[] = { 76 /* Device interface */ 77 DEVMETHOD(device_probe, clkbrd_probe), 78 DEVMETHOD(device_attach, clkbrd_attach), 79 DEVMETHOD(device_detach, clkbrd_detach), 80 81 { 0, 0 } 82}; 83 84static driver_t clkbrd_driver = { 85 "clkbrd", 86 clkbrd_methods, 87 sizeof(struct clkbrd_softc), 88}; 89 90DRIVER_MODULE(clkbrd, fhc, clkbrd_driver, clkbrd_devclass, 0, 0); 91 92static int 93clkbrd_probe(device_t dev) 94{ 95 96 if (strcmp(ofw_bus_get_name(dev), "clock-board") == 0) { 97 device_set_desc(dev, "Clock Board"); 98 return (0); 99 } 100 return (ENXIO); 101} 102 103static int 104clkbrd_attach(device_t dev) 105{ 106 struct clkbrd_softc *sc; 107 int i, slots; 108 uint8_t r; 109 110 sc = device_get_softc(dev); 111 sc->sc_dev = dev; 112 113 for (i = CLKBRD_CF; i <= CLKBRD_CLKVER; i++) { 114 sc->sc_rid[i] = i; 115 sc->sc_res[i] = bus_alloc_resource_any(sc->sc_dev, 116 SYS_RES_MEMORY, &sc->sc_rid[i], RF_ACTIVE); 117 if (sc->sc_res[i] == NULL) { 118 if (i != CLKBRD_CLKVER) { 119 device_printf(sc->sc_dev, 120 "could not allocate resource %d\n", i); 121 goto fail; 122 } 123 continue; 124 } 125 sc->sc_bt[i] = rman_get_bustag(sc->sc_res[i]); 126 sc->sc_bh[i] = rman_get_bushandle(sc->sc_res[i]); 127 if (i == CLKBRD_CLKVER) 128 sc->sc_flags |= CLKBRD_HAS_CLKVER; 129 } 130 131 slots = 4; 132 r = bus_space_read_1(sc->sc_bt[CLKBRD_CLK], sc->sc_bh[CLKBRD_CLK], 133 CLK_STS1); 134 switch (r & CLK_STS1_SLOTS_MASK) { 135 case CLK_STS1_SLOTS_16: 136 slots = 16; 137 break; 138 case CLK_STS1_SLOTS_8: 139 slots = 8; 140 break; 141 case CLK_STS1_SLOTS_4: 142 if (sc->sc_flags & CLKBRD_HAS_CLKVER) { 143 r = bus_space_read_1(sc->sc_bt[CLKBRD_CLKVER], 144 sc->sc_bh[CLKBRD_CLKVER], CLKVER_SLOTS); 145 if (r != 0 && 146 (r & CLKVER_SLOTS_MASK) == CLKVER_SLOTS_PLUS) 147 slots = 5; 148 } 149 } 150 151 device_printf(sc->sc_dev, "Sun Enterprise Exx00 machine: %d slots\n", 152 slots); 153 154 sc->sc_clk_ctrl = bus_space_read_1(sc->sc_bt[CLKBRD_CLK], 155 sc->sc_bh[CLKBRD_CLK], CLK_CTRL); 156 sc->sc_led_dev = led_create(clkbrd_led_func, sc, "clockboard"); 157 158 return (0); 159 160 fail: 161 clkbrd_free_resources(sc); 162 163 return (ENXIO); 164} 165 166static int 167clkbrd_detach(device_t dev) 168{ 169 struct clkbrd_softc *sc; 170 171 sc = device_get_softc(dev); 172 173 led_destroy(sc->sc_led_dev); 174 bus_space_write_1(sc->sc_bt[CLKBRD_CLK], sc->sc_bh[CLKBRD_CLK], 175 CLK_CTRL, sc->sc_clk_ctrl); 176 bus_space_read_1(sc->sc_bt[CLKBRD_CLK], sc->sc_bh[CLKBRD_CLK], 177 CLK_CTRL); 178 clkbrd_free_resources(sc); 179 180 return (0); 181} 182 183static void 184clkbrd_free_resources(struct clkbrd_softc *sc) 185{ 186 int i; 187 188 for (i = CLKBRD_CF; i <= CLKBRD_CLKVER; i++) 189 if (sc->sc_res[i] != NULL) 190 bus_release_resource(sc->sc_dev, SYS_RES_MEMORY, 191 sc->sc_rid[i], sc->sc_res[i]); 192} 193 194static void 195clkbrd_led_func(void *arg, int onoff) 196{ 197 struct clkbrd_softc *sc; 198 uint8_t r; 199 200 sc = (struct clkbrd_softc *)arg; 201 202 r = bus_space_read_1(sc->sc_bt[CLKBRD_CLK], sc->sc_bh[CLKBRD_CLK], 203 CLK_CTRL); 204 if (onoff) 205 r |= CLK_CTRL_RLED; 206 else 207 r &= ~CLK_CTRL_RLED; 208 bus_space_write_1(sc->sc_bt[CLKBRD_CLK], sc->sc_bh[CLKBRD_CLK], 209 CLK_CTRL, r); 210 bus_space_read_1(sc->sc_bt[CLKBRD_CLK], sc->sc_bh[CLKBRD_CLK], 211 CLK_CTRL); 212} 213