epic.c revision 202006
145386Swpaul/*- 245386Swpaul * Copyright (c) 2009 Marius Strobl <marius@FreeBSD.org> 345386Swpaul * All rights reserved. 445386Swpaul * 545386Swpaul * Redistribution and use in source and binary forms, with or without 645386Swpaul * modification, are permitted provided that the following conditions 745386Swpaul * are met: 845386Swpaul * 1. Redistributions of source code must retain the above copyright 945386Swpaul * notice, this list of conditions and the following disclaimer. 1045386Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1145386Swpaul * notice, this list of conditions and the following disclaimer in the 1245386Swpaul * documentation and/or other materials provided with the distribution. 1345386Swpaul * 1445386Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1545386Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1645386Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1745386Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1845386Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1945386Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2045386Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2145386Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2245386Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2345386Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2445386Swpaul * SUCH DAMAGE. 2545386Swpaul */ 2645386Swpaul 2745386Swpaul#include <sys/cdefs.h> 2845386Swpaul__FBSDID("$FreeBSD: head/sys/sparc64/ebus/epic.c 202006 2010-01-10 15:44:48Z marius $"); 2945386Swpaul 3045386Swpaul#include <sys/param.h> 3145386Swpaul#include <sys/systm.h> 3245386Swpaul#include <sys/bus.h> 3345386Swpaul#include <sys/kernel.h> 3445386Swpaul#include <sys/lock.h> 3545386Swpaul#include <sys/module.h> 3645386Swpaul#include <sys/mutex.h> 3745386Swpaul#include <sys/resource.h> 3845386Swpaul#include <sys/rman.h> 3945386Swpaul 4045386Swpaul#include <dev/led/led.h> 4145386Swpaul#include <dev/ofw/ofw_bus.h> 4245386Swpaul 4345386Swpaul#include <machine/bus.h> 4445386Swpaul#include <machine/resource.h> 4545386Swpaul 4645386Swpaul#define EPIC_DELAY 10000 4745386Swpaul 4845386Swpaul#define EPIC_NREG 1 4945386Swpaul#define EPIC_FW_LED 0 5045386Swpaul 5145386Swpaul#define EPIC_FW_LED_DATA 0x40 5245386Swpaul#define EPIC_FW_LED_ADDR 0x41 5345386Swpaul#define EPIC_FW_LED_WRITE_MASK 0x80 5445386Swpaul 5545386Swpaul#define EPIC_FW_VERSION 0x05 5645386Swpaul#define EPIC_LED_STATE0 0x06 5745386Swpaul 5845386Swpaul#define EPIC_LED_ALERT_MASK 0x0c 5945386Swpaul#define EPIC_LED_ALERT_OFF 0x00 6045386Swpaul#define EPIC_LED_ALERT_ON 0x04 6145386Swpaul 6245386Swpaul#define EPIC_LED_POWER_MASK 0x30 6345386Swpaul#define EPIC_LED_POWER_OFF 0x00 6445386Swpaul#define EPIC_LED_POWER_ON 0x10 6545386Swpaul#define EPIC_LED_POWER_SB_BLINK 0x20 6645386Swpaul#define EPIC_LED_POWER_FAST_BLINK 0x30 6745386Swpaul 6845386Swpaulstatic struct resource_spec epic_res_spec[] = { 6945386Swpaul { SYS_RES_MEMORY, EPIC_FW_LED, RF_ACTIVE }, 7045386Swpaul { -1, 0 } 7145386Swpaul}; 7245386Swpaul 7345386Swpaulstruct epic_softc { 7445386Swpaul struct mtx sc_mtx; 7545386Swpaul struct resource *sc_res[EPIC_NREG]; 7645386Swpaul struct cdev *sc_led_dev_alert; 7745386Swpaul struct cdev *sc_led_dev_power; 7845386Swpaul}; 7945386Swpaul 8045386Swpaul#define EPIC_FW_LED_READ(sc, off) ({ \ 8145386Swpaul uint8_t __val; \ 8245386Swpaul bus_write_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_ADDR, (off));\ 8345386Swpaul bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_ADDR, 1, \ 8445386Swpaul BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ 8545386Swpaul DELAY(EPIC_DELAY); \ 8645386Swpaul __val = bus_read_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_DATA);\ 8745386Swpaul bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_DATA, 1, \ 8845386Swpaul BUS_SPACE_BARRIER_READ); \ 8945386Swpaul DELAY(EPIC_DELAY); \ 9045386Swpaul __val; \ 9145386Swpaul}) 9245386Swpaul 9345386Swpaul#define EPIC_FW_LED_WRITE(sc, off, mask, val) do { \ 9445386Swpaul bus_write_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_ADDR, (off));\ 9545386Swpaul bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_ADDR, 1, \ 9645386Swpaul BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ 9745386Swpaul DELAY(EPIC_DELAY); \ 9845386Swpaul bus_write_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_WRITE_MASK, \ 9945386Swpaul (mask)); \ 10045386Swpaul bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_WRITE_MASK, \ 10145386Swpaul 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ 10245386Swpaul DELAY(EPIC_DELAY); \ 10345386Swpaul bus_write_1((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_DATA, (val));\ 10445386Swpaul bus_barrier((sc)->sc_res[EPIC_FW_LED], EPIC_FW_LED_DATA, 1, \ 10545386Swpaul BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ 10645386Swpaul DELAY(EPIC_DELAY); \ 10745386Swpaul} while (0) 10845386Swpaul 10945386Swpaul#define EPIC_LOCK_INIT(sc) \ 11045386Swpaul mtx_init(&(sc)->sc_mtx, "epic mtx", NULL, MTX_DEF) 11145386Swpaul#define EPIC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) 11245386Swpaul#define EPIC_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 11345386Swpaul#define EPIC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 11445386Swpaul 11545386Swpaulstatic device_probe_t epic_probe; 11645386Swpaulstatic device_attach_t epic_attach; 11745386Swpaulstatic device_detach_t epic_detach; 11845386Swpaul 11945386Swpaulstatic void epic_led_alert(void *arg, int onoff); 12045386Swpaulstatic void epic_led_power(void *arg, int onoff); 12145386Swpaul 12245386Swpaulstatic device_method_t epic_methods[] = { 12345386Swpaul /* Device interface */ 12445386Swpaul DEVMETHOD(device_probe, epic_probe), 12545386Swpaul DEVMETHOD(device_attach, epic_attach), 12645386Swpaul DEVMETHOD(device_detach, epic_detach), 12745386Swpaul 12845386Swpaul KOBJMETHOD_END 12945386Swpaul}; 13045386Swpaul 13145386Swpaulstatic devclass_t epic_devclass; 13245386Swpaul 13345386SwpaulDEFINE_CLASS_0(epic, epic_driver, epic_methods, 13445386Swpaul sizeof(struct epic_softc)); 13545386SwpaulDRIVER_MODULE(epic, ebus, epic_driver, epic_devclass, 0, 0); 13645386Swpaul 13745386Swpaulstatic int 13845386Swpaulepic_probe(device_t dev) 13945386Swpaul{ 14045386Swpaul const char* compat; 14145386Swpaul 14245386Swpaul compat = ofw_bus_get_compat(dev); 14345386Swpaul if (compat != NULL && strcmp(ofw_bus_get_name(dev), 14445386Swpaul "env-monitor") == 0 && strcmp(compat, "epic") == 0) { 14545386Swpaul device_set_desc(dev, "Sun Fire V215/V245 LEDs"); 14645386Swpaul return (BUS_PROBE_DEFAULT); 14745386Swpaul } 14845386Swpaul return (ENXIO); 14945386Swpaul} 15045386Swpaul 15145386Swpaulstatic int 15245386Swpaulepic_attach(device_t dev) 15345386Swpaul{ 15445386Swpaul struct epic_softc *sc; 15545386Swpaul 15645386Swpaul sc = device_get_softc(dev); 15745386Swpaul if (bus_alloc_resources(dev, epic_res_spec, sc->sc_res)) { 15845386Swpaul device_printf(dev, "failed to allocate resources\n"); 15945386Swpaul bus_release_resources(dev, epic_res_spec, sc->sc_res); 16045386Swpaul return (ENXIO); 16145386Swpaul } 16245386Swpaul 16345386Swpaul EPIC_LOCK_INIT(sc); 16445386Swpaul 16545386Swpaul if (bootverbose) 16645386Swpaul device_printf(dev, "version 0x%x\n", 16745386Swpaul EPIC_FW_LED_READ(sc, EPIC_FW_VERSION)); 16845386Swpaul 16945386Swpaul sc->sc_led_dev_alert = led_create(epic_led_alert, sc, "alert"); 17045386Swpaul sc->sc_led_dev_power = led_create(epic_led_power, sc, "power"); 17145386Swpaul 17245386Swpaul return (0); 17345386Swpaul} 17445386Swpaul 17545386Swpaulstatic int 17645386Swpaulepic_detach(device_t dev) 17745386Swpaul{ 17845386Swpaul struct epic_softc *sc; 17945386Swpaul 18045386Swpaul sc = device_get_softc(dev); 18145386Swpaul 18245386Swpaul led_destroy(sc->sc_led_dev_alert); 18345386Swpaul led_destroy(sc->sc_led_dev_power); 18445386Swpaul 18545386Swpaul bus_release_resources(dev, epic_res_spec, sc->sc_res); 18645386Swpaul 18745386Swpaul EPIC_LOCK_DESTROY(sc); 18845386Swpaul 18945386Swpaul return (0); 19045386Swpaul} 19145386Swpaul 19245386Swpaulstatic void 19345386Swpaulepic_led_alert(void *arg, int onoff) 19445386Swpaul{ 19545386Swpaul struct epic_softc *sc; 19645386Swpaul 19745386Swpaul sc = (struct epic_softc *)arg; 19845386Swpaul 19945386Swpaul EPIC_LOCK(sc); 20045386Swpaul EPIC_FW_LED_WRITE(sc, EPIC_LED_STATE0, EPIC_LED_ALERT_MASK, 20145386Swpaul onoff ? EPIC_LED_ALERT_ON : EPIC_LED_ALERT_OFF); 20245386Swpaul EPIC_UNLOCK(sc); 20345386Swpaul} 20445386Swpaul 20545386Swpaulstatic void 20645386Swpaulepic_led_power(void *arg, int onoff) 20745386Swpaul{ 20845386Swpaul struct epic_softc *sc; 20945386Swpaul 21045386Swpaul sc = (struct epic_softc *)arg; 21145386Swpaul 21245386Swpaul EPIC_LOCK(sc); 21345386Swpaul EPIC_FW_LED_WRITE(sc, EPIC_LED_STATE0, EPIC_LED_POWER_MASK, 21445386Swpaul onoff ? EPIC_LED_POWER_ON : EPIC_LED_POWER_OFF); 21545386Swpaul EPIC_UNLOCK(sc); 21645386Swpaul} 21745386Swpaul