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 * without modification, immediately at the beginning of the file. 11 * 2. The name of the author may not be used to endorse or promote products 12 * derived from this software without specific prior written permission. 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 FOR 18 * 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 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD$"); 30 31#include <sys/param.h> 32#include <sys/kernel.h> 33#include <sys/bus.h> 34#include <sys/module.h> 35 36#include <dev/fdt/fdt_common.h> 37#include <dev/ofw/openfirm.h> 38#include <dev/ofw/ofw_bus.h> 39#include <dev/ofw/ofw_bus_subr.h> 40 41#include <mips/mediatek/fdt_reset.h> 42#include <mips/mediatek/mtk_sysctl.h> 43 44#include "fdt_reset_if.h" 45 46static const struct ofw_compat_data compat_data[] = { 47 { "ralink,rt2880-reset", 1 }, 48 49 /* Sentinel */ 50 { NULL, 0 } 51}; 52 53static int 54mtk_reset_probe(device_t dev) 55{ 56 57 if (!ofw_bus_status_okay(dev)) 58 return (ENXIO); 59 60 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 61 return (ENXIO); 62 63 device_set_desc(dev, "MTK Reset Controller"); 64 65 return (0); 66} 67 68static int 69mtk_reset_attach(device_t dev) 70{ 71 72 if (device_get_unit(dev) != 0) { 73 device_printf(dev, "Only one reset control allowed\n"); 74 return (ENXIO); 75 } 76 77 fdt_reset_register_provider(dev); 78 79 return (0); 80} 81 82#define RESET_ASSERT 1 83#define RESET_DEASSERT 0 84 85static int 86mtk_reset_set(device_t dev, int index, int value) 87{ 88 uint32_t mask; 89 90 /* index 0 is SoC reset, indices 1 - 31 are valid peripheral resets */ 91 if (index < 1 || index > 31) 92 return (EINVAL); 93 94 mask = (1u << index); 95 96 if (value == RESET_ASSERT) 97 mtk_sysctl_clr_set(SYSCTL_RSTCTRL, 0, mask); 98 else 99 mtk_sysctl_clr_set(SYSCTL_RSTCTRL, mask, 0); 100 101 return (0); 102} 103 104static int 105mtk_reset_assert(device_t dev, int index) 106{ 107 108 return mtk_reset_set(dev, index, RESET_ASSERT); 109} 110 111static int 112mtk_reset_deassert(device_t dev, int index) 113{ 114 115 return mtk_reset_set(dev, index, RESET_DEASSERT); 116} 117 118static device_method_t mtk_reset_methods[] = { 119 DEVMETHOD(device_probe, mtk_reset_probe), 120 DEVMETHOD(device_attach, mtk_reset_attach), 121 122 /* fdt_reset interface */ 123 DEVMETHOD(fdt_reset_assert, mtk_reset_assert), 124 DEVMETHOD(fdt_reset_deassert, mtk_reset_deassert), 125 126 DEVMETHOD_END 127}; 128 129static driver_t mtk_reset_driver = { 130 "rstctrl", 131 mtk_reset_methods, 132 0, 133}; 134static devclass_t mtk_reset_devclass; 135 136EARLY_DRIVER_MODULE(mtk_reset, simplebus, mtk_reset_driver, mtk_reset_devclass, 137 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_EARLY); 138 139MODULE_DEPEND(mtk_reset, mtk_sysctl, 1, 1, 1); 140