1252391Sray/*- 2252391Sray * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com> 3252391Sray * All rights reserved. 4252391Sray * 5252391Sray * Redistribution and use in source and binary forms, with or without 6252391Sray * modification, are permitted provided that the following conditions 7252391Sray * are met: 8252391Sray * 1. Redistributions of source code must retain the above copyright 9252391Sray * notice, this list of conditions and the following disclaimer. 10252391Sray * 2. Redistributions in binary form must reproduce the above copyright 11252391Sray * notice, this list of conditions and the following disclaimer in the 12252391Sray * documentation and/or other materials provided with the distribution. 13252391Sray * 14252391Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15252391Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16252391Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17252391Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18252391Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19252391Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20252391Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21252391Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22252391Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23252391Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24252391Sray * SUCH DAMAGE. 25252391Sray */ 26252391Sray 27252391Sray/* 28252391Sray * This module just enables Exynos MCT, so ARMv7 Generic Timer will works 29252391Sray */ 30252391Sray 31252391Sray#include <sys/cdefs.h> 32252391Sray__FBSDID("$FreeBSD$"); 33252391Sray 34252391Sray#include <sys/param.h> 35252391Sray#include <sys/systm.h> 36252391Sray#include <sys/bus.h> 37252391Sray#include <sys/kernel.h> 38252391Sray#include <sys/module.h> 39252391Sray#include <sys/malloc.h> 40252391Sray#include <sys/rman.h> 41252391Sray#include <sys/timeet.h> 42252391Sray#include <sys/timetc.h> 43252391Sray#include <sys/watchdog.h> 44252391Sray#include <machine/bus.h> 45252391Sray#include <machine/cpu.h> 46252391Sray#include <machine/intr.h> 47252391Sray 48252391Sray#include <dev/ofw/openfirm.h> 49252391Sray#include <dev/ofw/ofw_bus.h> 50252391Sray#include <dev/ofw/ofw_bus_subr.h> 51252391Sray 52252391Sray#include <machine/bus.h> 53252391Sray 54252391Sray#define MCT_CTRL_START (1 << 8) 55252391Sray#define MCT_CTRL (0x240) 56252391Sray#define MCT_WRITE_STAT (0x24C) 57252391Sray 58252391Sraystruct arm_tmr_softc { 59252391Sray struct resource *tmr_res[1]; 60252391Sray bus_space_tag_t bst; 61252391Sray bus_space_handle_t bsh; 62252391Sray}; 63252391Sray 64252391Sraystatic struct resource_spec arm_tmr_spec[] = { 65252391Sray { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Timer registers */ 66252391Sray { -1, 0 } 67252391Sray}; 68252391Sray 69252391Sraystatic int 70252391Srayarm_tmr_probe(device_t dev) 71252391Sray{ 72261410Sian 73261410Sian if (!ofw_bus_status_okay(dev)) 74261410Sian return (ENXIO); 75261410Sian 76252391Sray if (!ofw_bus_is_compatible(dev, "exynos,mct")) 77252391Sray return (ENXIO); 78252391Sray 79252391Sray device_set_desc(dev, "Exynos MPCore Timer"); 80252391Sray return (BUS_PROBE_DEFAULT); 81252391Sray} 82252391Sray 83252391Sraystatic int 84252391Srayarm_tmr_attach(device_t dev) 85252391Sray{ 86252391Sray struct arm_tmr_softc *sc; 87252391Sray int reg, i; 88252391Sray int mask; 89252391Sray 90252391Sray sc = device_get_softc(dev); 91252391Sray 92252391Sray if (bus_alloc_resources(dev, arm_tmr_spec, sc->tmr_res)) { 93252391Sray device_printf(dev, "could not allocate resources\n"); 94252391Sray return (ENXIO); 95252391Sray } 96252391Sray 97252391Sray /* Timer interface */ 98252391Sray sc->bst = rman_get_bustag(sc->tmr_res[0]); 99252391Sray sc->bsh = rman_get_bushandle(sc->tmr_res[0]); 100252391Sray 101252391Sray reg = bus_space_read_4(sc->bst, sc->bsh, MCT_CTRL); 102252391Sray reg |= MCT_CTRL_START; 103252391Sray bus_space_write_4(sc->bst, sc->bsh, MCT_CTRL, reg); 104252391Sray 105252391Sray mask = (1 << 16); 106252391Sray 107252391Sray /* Wait 10 times until written value is applied */ 108252391Sray for (i = 0; i < 10; i++) { 109252391Sray reg = bus_space_read_4(sc->bst, sc->bsh, MCT_WRITE_STAT); 110252391Sray if (reg & mask) { 111252391Sray bus_space_write_4(sc->bst, sc->bsh, 112252391Sray MCT_WRITE_STAT, mask); 113252391Sray return (0); 114252391Sray } 115252391Sray cpufunc_nullop(); 116252391Sray } 117252391Sray 118252391Sray /* NOTREACHED */ 119252391Sray 120252391Sray panic("Can't enable timer\n"); 121252391Sray} 122252391Sray 123252391Sraystatic device_method_t arm_tmr_methods[] = { 124252391Sray DEVMETHOD(device_probe, arm_tmr_probe), 125252391Sray DEVMETHOD(device_attach, arm_tmr_attach), 126252391Sray { 0, 0 } 127252391Sray}; 128252391Sray 129252391Sraystatic driver_t arm_tmr_driver = { 130263431Sbr "mct", 131252391Sray arm_tmr_methods, 132252391Sray sizeof(struct arm_tmr_softc), 133252391Sray}; 134252391Sray 135252391Sraystatic devclass_t arm_tmr_devclass; 136252391Sray 137263431SbrDRIVER_MODULE(mct, simplebus, arm_tmr_driver, arm_tmr_devclass, 0, 0); 138