1202006Smarius/*- 2202006Smarius * Copyright (c) 2009 Marius Strobl <marius@FreeBSD.org> 3202006Smarius * All rights reserved. 4202006Smarius * 5202006Smarius * Redistribution and use in source and binary forms, with or without 6202006Smarius * modification, are permitted provided that the following conditions 7202006Smarius * are met: 8202006Smarius * 1. Redistributions of source code must retain the above copyright 9202006Smarius * notice, this list of conditions and the following disclaimer. 10202006Smarius * 2. Redistributions in binary form must reproduce the above copyright 11202006Smarius * notice, this list of conditions and the following disclaimer in the 12202006Smarius * documentation and/or other materials provided with the distribution. 13202006Smarius * 14202006Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15202006Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16202006Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17202006Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18202006Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19202006Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20202006Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21202006Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22202006Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23202006Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24202006Smarius * SUCH DAMAGE. 25202006Smarius */ 26202006Smarius 27202006Smarius#include <sys/cdefs.h> 28202006Smarius__FBSDID("$FreeBSD$"); 29202006Smarius 30202006Smarius#include <sys/param.h> 31202006Smarius#include <sys/systm.h> 32202006Smarius#include <sys/bus.h> 33202006Smarius#include <sys/kernel.h> 34202006Smarius#include <sys/lock.h> 35202006Smarius#include <sys/module.h> 36202006Smarius#include <sys/mutex.h> 37202006Smarius#include <sys/resource.h> 38202006Smarius#include <sys/rman.h> 39202006Smarius 40202006Smarius#include <dev/led/led.h> 41202006Smarius#include <dev/ofw/ofw_bus.h> 42202006Smarius 43202006Smarius#include <machine/bus.h> 44202006Smarius#include <machine/resource.h> 45202006Smarius 46202006Smarius#define EPIC_DELAY 10000 47202006Smarius 48202006Smarius#define EPIC_NREG 1 49202006Smarius#define EPIC_FW_LED 0 50202006Smarius 51202006Smarius#define EPIC_FW_LED_DATA 0x40 52202006Smarius#define EPIC_FW_LED_ADDR 0x41 53202006Smarius#define EPIC_FW_LED_WRITE_MASK 0x80 54202006Smarius 55202006Smarius#define EPIC_FW_VERSION 0x05 56202006Smarius#define EPIC_LED_STATE0 0x06 57202006Smarius 58202006Smarius#define EPIC_LED_ALERT_MASK 0x0c 59202006Smarius#define EPIC_LED_ALERT_OFF 0x00 60202006Smarius#define EPIC_LED_ALERT_ON 0x04 61202006Smarius 62202006Smarius#define EPIC_LED_POWER_MASK 0x30 63202006Smarius#define EPIC_LED_POWER_OFF 0x00 64202006Smarius#define EPIC_LED_POWER_ON 0x10 65202006Smarius#define EPIC_LED_POWER_SB_BLINK 0x20 66202006Smarius#define EPIC_LED_POWER_FAST_BLINK 0x30 67202006Smarius 68202006Smariusstatic struct resource_spec epic_res_spec[] = { 69202006Smarius { SYS_RES_MEMORY, EPIC_FW_LED, RF_ACTIVE }, 70202006Smarius { -1, 0 } 71202006Smarius}; 72202006Smarius 73202006Smariusstruct epic_softc { 74202006Smarius struct mtx sc_mtx; 75202006Smarius struct resource *sc_res[EPIC_NREG]; 76202006Smarius struct cdev *sc_led_dev_alert; 77202006Smarius struct cdev *sc_led_dev_power; 78202006Smarius}; 79202006Smarius 80202006Smarius#define EPIC_FW_LED_READ(sc, off) ({ \ 81202006Smarius uint8_t __val; \ 82202006Smarius bus_write_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_ADDR, (off));\ 83202006Smarius bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_ADDR, 1, \ 84202006Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ 85202006Smarius DELAY(EPIC_DELAY); \ 86202006Smarius __val = bus_read_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_DATA);\ 87202006Smarius bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_DATA, 1, \ 88202006Smarius BUS_SPACE_BARRIER_READ); \ 89202006Smarius DELAY(EPIC_DELAY); \ 90202006Smarius __val; \ 91202006Smarius}) 92202006Smarius 93202006Smarius#define EPIC_FW_LED_WRITE(sc, off, mask, val) do { \ 94202006Smarius bus_write_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_ADDR, (off));\ 95202006Smarius bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_ADDR, 1, \ 96202006Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ 97202006Smarius DELAY(EPIC_DELAY); \ 98202006Smarius bus_write_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_WRITE_MASK, \ 99202006Smarius (mask)); \ 100202006Smarius bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_WRITE_MASK, \ 101202006Smarius 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ 102202006Smarius DELAY(EPIC_DELAY); \ 103202006Smarius bus_write_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_DATA, (val));\ 104202006Smarius bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_DATA, 1, \ 105202006Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ 106202006Smarius DELAY(EPIC_DELAY); \ 107202006Smarius} while (0) 108202006Smarius 109202006Smarius#define EPIC_LOCK_INIT(sc) \ 110202006Smarius mtx_init(&(sc)->sc_mtx, "epic mtx", NULL, MTX_DEF) 111202006Smarius#define EPIC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) 112202006Smarius#define EPIC_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 113202006Smarius#define EPIC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 114202006Smarius 115202006Smariusstatic device_probe_t epic_probe; 116202006Smariusstatic device_attach_t epic_attach; 117202006Smariusstatic device_detach_t epic_detach; 118202006Smarius 119202006Smariusstatic void epic_led_alert(void *arg, int onoff); 120202006Smariusstatic void epic_led_power(void *arg, int onoff); 121202006Smarius 122202006Smariusstatic device_method_t epic_methods[] = { 123202006Smarius /* Device interface */ 124202006Smarius DEVMETHOD(device_probe, epic_probe), 125202006Smarius DEVMETHOD(device_attach, epic_attach), 126202006Smarius DEVMETHOD(device_detach, epic_detach), 127202006Smarius 128227848Smarius DEVMETHOD_END 129202006Smarius}; 130202006Smarius 131202006Smariusstatic devclass_t epic_devclass; 132202006Smarius 133202006SmariusDEFINE_CLASS_0(epic, epic_driver, epic_methods, 134202006Smarius sizeof(struct epic_softc)); 135202006SmariusDRIVER_MODULE(epic, ebus, epic_driver, epic_devclass, 0, 0); 136202006Smarius 137202006Smariusstatic int 138202006Smariusepic_probe(device_t dev) 139202006Smarius{ 140202006Smarius const char* compat; 141202006Smarius 142202006Smarius compat = ofw_bus_get_compat(dev); 143202006Smarius if (compat != NULL && strcmp(ofw_bus_get_name(dev), 144202006Smarius "env-monitor") == 0 && strcmp(compat, "epic") == 0) { 145202006Smarius device_set_desc(dev, "Sun Fire V215/V245 LEDs"); 146202006Smarius return (BUS_PROBE_DEFAULT); 147202006Smarius } 148202006Smarius return (ENXIO); 149202006Smarius} 150202006Smarius 151202006Smariusstatic int 152202006Smariusepic_attach(device_t dev) 153202006Smarius{ 154202006Smarius struct epic_softc *sc; 155202006Smarius 156202006Smarius sc = device_get_softc(dev); 157202006Smarius if (bus_alloc_resources(dev, epic_res_spec, sc->sc_res)) { 158202006Smarius device_printf(dev, "failed to allocate resources\n"); 159202006Smarius bus_release_resources(dev, epic_res_spec, sc->sc_res); 160202006Smarius return (ENXIO); 161202006Smarius } 162202006Smarius 163202006Smarius EPIC_LOCK_INIT(sc); 164202006Smarius 165202006Smarius if (bootverbose) 166202006Smarius device_printf(dev, "version 0x%x\n", 167202006Smarius EPIC_FW_LED_READ(sc, EPIC_FW_VERSION)); 168202006Smarius 169202006Smarius sc->sc_led_dev_alert = led_create(epic_led_alert, sc, "alert"); 170202006Smarius sc->sc_led_dev_power = led_create(epic_led_power, sc, "power"); 171202006Smarius 172202006Smarius return (0); 173202006Smarius} 174202006Smarius 175202006Smariusstatic int 176202006Smariusepic_detach(device_t dev) 177202006Smarius{ 178202006Smarius struct epic_softc *sc; 179202006Smarius 180202006Smarius sc = device_get_softc(dev); 181202006Smarius 182202006Smarius led_destroy(sc->sc_led_dev_alert); 183202006Smarius led_destroy(sc->sc_led_dev_power); 184202006Smarius 185202006Smarius bus_release_resources(dev, epic_res_spec, sc->sc_res); 186202006Smarius 187202006Smarius EPIC_LOCK_DESTROY(sc); 188202006Smarius 189202006Smarius return (0); 190202006Smarius} 191202006Smarius 192202006Smariusstatic void 193202006Smariusepic_led_alert(void *arg, int onoff) 194202006Smarius{ 195202006Smarius struct epic_softc *sc; 196202006Smarius 197202006Smarius sc = (struct epic_softc *)arg; 198202006Smarius 199202006Smarius EPIC_LOCK(sc); 200202006Smarius EPIC_FW_LED_WRITE(sc, EPIC_LED_STATE0, EPIC_LED_ALERT_MASK, 201202006Smarius onoff ? EPIC_LED_ALERT_ON : EPIC_LED_ALERT_OFF); 202202006Smarius EPIC_UNLOCK(sc); 203202006Smarius} 204202006Smarius 205202006Smariusstatic void 206202006Smariusepic_led_power(void *arg, int onoff) 207202006Smarius{ 208202006Smarius struct epic_softc *sc; 209202006Smarius 210202006Smarius sc = (struct epic_softc *)arg; 211202006Smarius 212202006Smarius EPIC_LOCK(sc); 213202006Smarius EPIC_FW_LED_WRITE(sc, EPIC_LED_STATE0, EPIC_LED_POWER_MASK, 214202006Smarius onoff ? EPIC_LED_POWER_ON : EPIC_LED_POWER_OFF); 215202006Smarius EPIC_UNLOCK(sc); 216202006Smarius} 217