mtk_sysctl.c revision 302408
1/*- 2 * Copyright (c) 2016 Stanislav Galabov. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/11/sys/mips/mediatek/mtk_sysctl.c 297666 2016-04-07 11:02:49Z sgalabov $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/bus.h> 33#include <sys/interrupt.h> 34#include <sys/kernel.h> 35#include <sys/module.h> 36#include <sys/lock.h> 37#include <sys/mutex.h> 38#include <sys/rman.h> 39#include <sys/malloc.h> 40 41#include <machine/fdt.h> 42 43#include <dev/ofw/openfirm.h> 44#include <dev/ofw/ofw_bus.h> 45#include <dev/ofw/ofw_bus_subr.h> 46 47#include <mips/mediatek/mtk_sysctl.h> 48 49#include <dev/fdt/fdt_common.h> 50 51struct mtk_sysctl_softc { 52 device_t dev; 53 struct resource *mem_res; 54 int mem_rid; 55 struct mtx mtx; 56}; 57 58static struct mtk_sysctl_softc *mtk_sysctl_sc = NULL; 59 60static struct ofw_compat_data compat_data[] = { 61 { "ralink,rt2880-sysc", 1 }, 62 { "ralink,rt3050-sysc", 1 }, 63 { "ralink,rt3352-sysc", 1 }, 64 { "ralink,rt3883-sysc", 1 }, 65 { "ralink,rt5350-sysc", 1 }, 66 { "ralink,mt7620a-sysc", 1 }, 67 { "mtk,mt7621-sysc", 1 }, 68 69 /* Sentinel */ 70 { NULL, 0 } 71}; 72 73#define MTK_SYSCTL_LOCK(sc) mtx_lock_spin(&(sc)->mtx) 74#define MTK_SYSCTL_UNLOCK(sc) mtx_unlock_spin(&(sc)->mtx) 75#define MTK_SYSCTL_LOCK_INIT(sc) \ 76 mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \ 77 "mtk_sysctl", MTX_SPIN) 78#define MTK_SYSCTL_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx) 79 80static int 81mtk_sysctl_probe(device_t dev) 82{ 83 84 if (!ofw_bus_status_okay(dev)) 85 return (ENXIO); 86 87 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 88 return (ENXIO); 89 90 device_set_desc(dev, "MTK System Controller"); 91 92 return (BUS_PROBE_DEFAULT); 93} 94 95static int mtk_sysctl_detach(device_t); 96 97static int 98mtk_sysctl_attach(device_t dev) 99{ 100 struct mtk_sysctl_softc *sc = device_get_softc(dev); 101 102 if (device_get_unit(dev) != 0 || mtk_sysctl_sc != NULL) { 103 device_printf(dev, "Only one sysctl module supported\n"); 104 return (ENXIO); 105 } 106 107 mtk_sysctl_sc = sc; 108 109 /* Map control/status registers. */ 110 sc->mem_rid = 0; 111 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 112 &sc->mem_rid, RF_ACTIVE); 113 114 if (sc->mem_res == NULL) { 115 device_printf(dev, "couldn't map memory\n"); 116 mtk_sysctl_detach(dev); 117 return (ENXIO); 118 } 119 120 sc->dev = dev; 121 122 MTK_SYSCTL_LOCK_INIT(sc); 123 124 return (0); 125} 126 127static int 128mtk_sysctl_detach(device_t dev) 129{ 130 struct mtk_sysctl_softc *sc = device_get_softc(dev); 131 132 if (sc->mem_res) 133 bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, 134 sc->mem_res); 135 136 MTK_SYSCTL_LOCK_DESTROY(sc); 137 138 return(0); 139} 140 141uint32_t 142mtk_sysctl_get(uint32_t reg) 143{ 144 uint32_t val; 145 146 MTK_SYSCTL_LOCK(mtk_sysctl_sc); 147 val = bus_read_4(mtk_sysctl_sc->mem_res, reg); 148 MTK_SYSCTL_UNLOCK(mtk_sysctl_sc); 149 150 return (val); 151} 152 153void 154mtk_sysctl_set(uint32_t reg, uint32_t val) 155{ 156 157 MTK_SYSCTL_LOCK(mtk_sysctl_sc); 158 bus_write_4(mtk_sysctl_sc->mem_res, reg, val); 159 MTK_SYSCTL_UNLOCK(mtk_sysctl_sc); 160} 161 162void 163mtk_sysctl_clr_set(uint32_t reg, uint32_t clr, uint32_t set) 164{ 165 uint32_t val; 166 167 MTK_SYSCTL_LOCK(mtk_sysctl_sc); 168 val = bus_read_4(mtk_sysctl_sc->mem_res, reg); 169 val &= ~(clr); 170 val |= set; 171 bus_write_4(mtk_sysctl_sc->mem_res, reg, val); 172 MTK_SYSCTL_UNLOCK(mtk_sysctl_sc); 173} 174 175static device_method_t mtk_sysctl_methods[] = { 176 DEVMETHOD(device_probe, mtk_sysctl_probe), 177 DEVMETHOD(device_attach, mtk_sysctl_attach), 178 DEVMETHOD(device_detach, mtk_sysctl_detach), 179 180 DEVMETHOD_END 181}; 182 183static driver_t mtk_sysctl_driver = { 184 "sysc", 185 mtk_sysctl_methods, 186 sizeof(struct mtk_sysctl_softc), 187}; 188static devclass_t mtk_sysctl_devclass; 189 190EARLY_DRIVER_MODULE(mtk_sysctl, simplebus, mtk_sysctl_driver, 191 mtk_sysctl_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_EARLY); 192