1/*- 2 * Copyright (c) 2010 Aleksandr Rybalko. 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$"); 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/rman.h> 37#include <sys/malloc.h> 38 39#include <machine/bus.h> 40 41#include <mips/rt305x/rt305xreg.h> 42#include <mips/rt305x/rt305x_sysctlvar.h> 43 44 45static int rt305x_sysctl_probe(device_t); 46static int rt305x_sysctl_attach(device_t); 47static int rt305x_sysctl_detach(device_t); 48 49 50static struct rt305x_sysctl_softc *rt305x_sysctl_softc = NULL; 51 52static void 53rt305x_sysctl_dump_config(device_t dev) 54{ 55 uint32_t val; 56#define DUMPREG(r) \ 57 val = rt305x_sysctl_get(r); printf(" " #r "=%#08x\n", val) 58 59 val = rt305x_sysctl_get(SYSCTL_CHIPID0_3); 60 printf("\tChip ID: \"%c%c%c%c", 61 (val >> 0 ) & 0xff, 62 (val >> 8 ) & 0xff, 63 (val >> 16) & 0xff, 64 (val >> 24) & 0xff); 65 val = rt305x_sysctl_get(SYSCTL_CHIPID4_7); 66 printf("%c%c%c%c\"\n", 67 (val >> 0 ) & 0xff, 68 (val >> 8 ) & 0xff, 69 (val >> 16) & 0xff, 70 (val >> 24) & 0xff); 71 72 DUMPREG(SYSCTL_SYSCFG); 73 if ( val & SYSCTL_SYSCFG_INIC_EE_SDRAM) 74 printf("\tGet SDRAM config from EEPROM\n"); 75 if ( val & SYSCTL_SYSCFG_INIC_8MB_SDRAM) 76 printf("\tBootstrap flag is set\n"); 77 printf("\tGE0 mode %u\n", 78 ((val & SYSCTL_SYSCFG_GE0_MODE_MASK) >> 79 SYSCTL_SYSCFG_GE0_MODE_SHIFT)); 80 if ( val & SYSCTL_SYSCFG_BOOT_ADDR_1F00) 81 printf("\tBoot from 0x1f000000\n"); 82 if ( val & SYSCTL_SYSCFG_BYPASS_PLL) 83 printf("\tBypass PLL\n"); 84 if ( val & SYSCTL_SYSCFG_BIG_ENDIAN) 85 printf("\tBig Endian\n"); 86 if ( val & SYSCTL_SYSCFG_CPU_CLK_SEL_384MHZ) 87 printf("\tClock is 384MHz\n"); 88 printf("\tBoot from %u\n", 89 ((val & SYSCTL_SYSCFG_BOOT_FROM_MASK) >> 90 SYSCTL_SYSCFG_BOOT_FROM_SHIFT)); 91 printf("\tBootstrap test code %u\n", 92 ((val & SYSCTL_SYSCFG_TEST_CODE_MASK) >> 93 SYSCTL_SYSCFG_TEST_CODE_SHIFT)); 94 printf("\tSRAM_CS mode %u\n", 95 ((val & SYSCTL_SYSCFG_SRAM_CS_MODE_MASK) >> 96 SYSCTL_SYSCFG_SRAM_CS_MODE_SHIFT)); 97 printf("\t%umA SDRAM_CLK driving\n", 98 (val & SYSCTL_SYSCFG_SDRAM_CLK_DRV)?12:8); 99 100 DUMPREG(SYSCTL_CLKCFG0); 101 printf("\tSDRAM_CLK_SKEW %uns\n", (val >> 30) & 0x03); 102 103 DUMPREG(SYSCTL_CLKCFG1); 104 if ( val & SYSCTL_CLKCFG1_PBUS_DIV_CLK_BY2) 105 printf("\tPbus clock is 1/2 of System clock\n"); 106 if ( val & SYSCTL_CLKCFG1_OTG_CLK_EN) 107 printf("\tUSB OTG clock is enabled\n"); 108 if ( val & SYSCTL_CLKCFG1_I2S_CLK_EN) 109 printf("\tI2S clock is enabled\n"); 110 printf("\tI2S clock is %s\n", 111 (val & SYSCTL_CLKCFG1_I2S_CLK_SEL_EXT)? 112 "external":"internal 15.625MHz"); 113 printf("\tI2S clock divider %u\n", 114 ((val & SYSCTL_CLKCFG1_I2S_CLK_DIV_MASK) >> 115 SYSCTL_CLKCFG1_I2S_CLK_DIV_SHIFT)); 116 if ( val & SYSCTL_CLKCFG1_PCM_CLK_EN) 117 printf("\tPCM clock is enabled\n"); 118 119 printf("\tPCM clock is %s\n", 120 (val & SYSCTL_CLKCFG1_PCM_CLK_SEL_EXT)? 121 "external":"internal 15.625MHz"); 122 printf("\tPCM clock divider %u\n", 123 ((val & SYSCTL_CLKCFG1_PCM_CLK_DIV_MASK) >> 124 SYSCTL_CLKCFG1_PCM_CLK_DIV_SHIFT)); 125 DUMPREG(SYSCTL_GPIOMODE); 126#undef DUMPREG 127 128 return; 129} 130 131static int 132rt305x_sysctl_probe(device_t dev) 133{ 134 device_set_desc(dev, "RT305X System Control driver"); 135 return (0); 136} 137 138static int 139rt305x_sysctl_attach(device_t dev) 140{ 141 struct rt305x_sysctl_softc *sc = device_get_softc(dev); 142 int error = 0; 143 144 KASSERT((device_get_unit(dev) == 0), 145 ("rt305x_sysctl: Only one sysctl module supported")); 146 147 if (rt305x_sysctl_softc != NULL) 148 return (ENXIO); 149 rt305x_sysctl_softc = sc; 150 151 152 /* Map control/status registers. */ 153 sc->mem_rid = 0; 154 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 155 &sc->mem_rid, RF_ACTIVE); 156 157 if (sc->mem_res == NULL) { 158 device_printf(dev, "couldn't map memory\n"); 159 error = ENXIO; 160 rt305x_sysctl_detach(dev); 161 return(error); 162 } 163#ifdef notyet 164 sc->irq_rid = 0; 165 if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 166 &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 167 device_printf(dev, "unable to allocate IRQ resource\n"); 168 return (ENXIO); 169 } 170 171 if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, 172 rt305x_sysctl_intr, NULL, sc, &sc->sysctl_ih))) { 173 device_printf(dev, 174 "WARNING: unable to register interrupt handler\n"); 175 return (ENXIO); 176 } 177#endif 178 rt305x_sysctl_dump_config(dev); 179 180 return (bus_generic_attach(dev)); 181} 182 183static int 184rt305x_sysctl_detach(device_t dev) 185{ 186 struct rt305x_sysctl_softc *sc = device_get_softc(dev); 187 188 bus_generic_detach(dev); 189 190 if (sc->mem_res) 191 bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, 192 sc->mem_res); 193#ifdef notyet 194 if (sc->irq_res) 195 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 196 sc->irq_res); 197#endif 198 return(0); 199} 200 201#ifdef notyet 202static int 203rt305x_sysctl_intr(void *arg) 204{ 205 return (FILTER_HANDLED); 206} 207#endif 208 209uint32_t 210rt305x_sysctl_get(uint32_t reg) 211{ 212 struct rt305x_sysctl_softc *sc = rt305x_sysctl_softc; 213 return (bus_read_4(sc->mem_res, reg)); 214} 215 216void 217rt305x_sysctl_set(uint32_t reg, uint32_t val) 218{ 219 struct rt305x_sysctl_softc *sc = rt305x_sysctl_softc; 220 bus_write_4(sc->mem_res, reg, val); 221 return; 222} 223 224 225static device_method_t rt305x_sysctl_methods[] = { 226 DEVMETHOD(device_probe, rt305x_sysctl_probe), 227 DEVMETHOD(device_attach, rt305x_sysctl_attach), 228 DEVMETHOD(device_detach, rt305x_sysctl_detach), 229 230 {0, 0}, 231}; 232 233static driver_t rt305x_sysctl_driver = { 234 "rt305x_sysctl", 235 rt305x_sysctl_methods, 236 sizeof(struct rt305x_sysctl_softc), 237}; 238static devclass_t rt305x_sysctl_devclass; 239 240DRIVER_MODULE(rt305x_sysctl, obio, rt305x_sysctl_driver, rt305x_sysctl_devclass, 0, 0); 241