1 /*- 2 * Copyright (c) 2015 Landon Fuller <landon@landonf.org> 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. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 /* 34 * Broadcom ChipCommon driver. 35 * 36 * With the exception of some very early chipsets, the ChipCommon core 37 * has been included in all HND SoCs and chipsets based on the siba(4) 38 * and bcma(4) interconnects, providing a common interface to chipset 39 * identification, bus enumeration, UARTs, clocks, watchdog interrupts, GPIO, 40 * flash, etc. 41 */ 42 43 #include <sys/param.h> 44 #include <sys/kernel.h> 45 #include <sys/bus.h> 46 #include <sys/module.h> 47 #include <sys/systm.h> 48 49 #include <machine/bus.h> 50 #include <sys/rman.h> 51 #include <machine/resource.h> 52 53 #include <dev/bhnd/bhnd.h> 54 55 #include "chipcreg.h" 56 #include "chipcvar.h" 57 58 devclass_t bhnd_chipc_devclass; /**< bhnd(4) chipcommon device class */ 59 60 static const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = { 61 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 62 { -1, -1, 0 } 63 }; 64 65 static struct bhnd_device_quirk chipc_quirks[]; 66 67 /* Supported device identifiers */ 68 static const struct bhnd_device chipc_devices[] = { 69 BHND_DEVICE(CC, "CC", chipc_quirks), 70 BHND_DEVICE_END 71 }; 72 73 74 /* Device quirks table */ 75 static struct bhnd_device_quirk chipc_quirks[] = { 76 { BHND_HWREV_RANGE (0, 21), CHIPC_QUIRK_ALWAYS_HAS_SPROM }, 77 { BHND_HWREV_EQ (22), CHIPC_QUIRK_SPROM_CHECK_CST_R22 }, 78 { BHND_HWREV_RANGE (23, 31), CHIPC_QUIRK_SPROM_CHECK_CST_R23 }, 79 { BHND_HWREV_GTE (35), CHIPC_QUIRK_SUPPORTS_NFLASH }, 80 BHND_DEVICE_QUIRK_END 81 }; 82 83 /* quirk and capability flag convenience macros */ 84 #define CHIPC_QUIRK(_sc, _name) \ 85 ((_sc)->quirks & CHIPC_QUIRK_ ## _name) 86 87 #define CHIPC_CAP(_sc, _name) \ 88 ((_sc)->caps & CHIPC_ ## _name) 89 90 #define CHIPC_ASSERT_QUIRK(_sc, name) \ 91 KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) 92 93 #define CHIPC_ASSERT_CAP(_sc, name) \ 94 KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set")) 95 96 static int 97 chipc_probe(device_t dev) 98 { 99 const struct bhnd_device *id; 100 101 id = bhnd_device_lookup(dev, chipc_devices, sizeof(chipc_devices[0])); 102 if (id == NULL) 103 return (ENXIO); 104 105 bhnd_set_default_core_desc(dev); 106 return (BUS_PROBE_DEFAULT); 107 } 108 109 static int 110 chipc_attach(device_t dev) 111 { 112 struct chipc_softc *sc; 113 bhnd_addr_t enum_addr; 114 uint32_t ccid_reg; 115 uint8_t chip_type; 116 int error; 117 118 sc = device_get_softc(dev); 119 sc->dev = dev; 120 sc->quirks = bhnd_device_quirks(dev, chipc_devices, 121 sizeof(chipc_devices[0])); 122 123 /* Allocate bus resources */ 124 memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec)); 125 if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res))) 126 return (error); 127 128 sc->core = sc->res[0]; 129 130 /* Fetch our chipset identification data */ 131 ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID); 132 chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS); 133 134 switch (chip_type) { 135 case BHND_CHIPTYPE_SIBA: 136 /* enumeration space starts at the ChipCommon register base. */ 137 enum_addr = rman_get_start(sc->core->res); 138 break; 139 case BHND_CHIPTYPE_BCMA: 140 case BHND_CHIPTYPE_BCMA_ALT: 141 enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR); 142 break; 143 default: 144 device_printf(dev, "unsupported chip type %hhu\n", chip_type); 145 error = ENODEV; 146 goto cleanup; 147 } 148 149 sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr); 150 151 /* Fetch capability and status register values */ 152 sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES); 153 sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST); 154 155 // TODO 156 switch (bhnd_chipc_nvram_src(dev)) { 157 case BHND_NVRAM_SRC_CIS: 158 device_printf(dev, "NVRAM source: CIS\n"); 159 break; 160 case BHND_NVRAM_SRC_SPROM: 161 device_printf(dev, "NVRAM source: SPROM\n"); 162 break; 163 case BHND_NVRAM_SRC_OTP: 164 device_printf(dev, "NVRAM source: OTP\n"); 165 break; 166 case BHND_NVRAM_SRC_NFLASH: 167 device_printf(dev, "NVRAM source: NFLASH\n"); 168 break; 169 case BHND_NVRAM_SRC_NONE: 170 device_printf(dev, "NVRAM source: NONE\n"); 171 break; 172 } 173 174 return (0); 175 176 cleanup: 177 bhnd_release_resources(dev, sc->rspec, sc->res); 178 return (error); 179 } 180 181 static int 182 chipc_detach(device_t dev) 183 { 184 struct chipc_softc *sc; 185 186 sc = device_get_softc(dev); 187 bhnd_release_resources(dev, sc->rspec, sc->res); 188 189 return (0); 190 } 191 192 static int 193 chipc_suspend(device_t dev) 194 { 195 return (0); 196 } 197 198 static int 199 chipc_resume(device_t dev) 200 { 201 return (0); 202 } 203 204 /** 205 * Use device-specific ChipStatus flags to determine the preferred NVRAM 206 * data source. 207 */ 208 static bhnd_nvram_src_t 209 chipc_nvram_src_chipst(struct chipc_softc *sc) 210 { 211 uint8_t nvram_sel; 212 213 CHIPC_ASSERT_QUIRK(sc, SPROM_CHECK_CHIPST); 214 215 if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R22)) { 216 // TODO: On these devices, the official driver code always 217 // assumes SPROM availability if CHIPC_CST_OTP_SEL is not 218 // set; we must review against the actual behavior of our 219 // BCM4312 hardware 220 nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R22); 221 } else if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R23)) { 222 nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R23); 223 } else { 224 panic("invalid CST OTP/SPROM chipc quirk flags"); 225 } 226 device_printf(sc->dev, "querying chipst for 0x%x, 0x%x\n", sc->ccid.chip_id, sc->cst); 227 228 switch (nvram_sel) { 229 case CHIPC_CST_DEFCIS_SEL: 230 return (BHND_NVRAM_SRC_CIS); 231 232 case CHIPC_CST_SPROM_SEL: 233 case CHIPC_CST_OTP_PWRDN: 234 return (BHND_NVRAM_SRC_SPROM); 235 236 case CHIPC_CST_OTP_SEL: 237 return (BHND_NVRAM_SRC_OTP); 238 239 default: 240 device_printf(sc->dev, "unrecognized OTP/SPROM type 0x%hhx", 241 nvram_sel); 242 return (BHND_NVRAM_SRC_NONE); 243 } 244 } 245 246 /** 247 * Determine the preferred NVRAM data source. 248 */ 249 static bhnd_nvram_src_t 250 chipc_nvram_src(device_t dev) 251 { 252 struct chipc_softc *sc; 253 uint32_t srom_ctrl; 254 255 sc = device_get_softc(dev); 256 257 /* Very early devices always included a SPROM */ 258 if (CHIPC_QUIRK(sc, ALWAYS_HAS_SPROM)) 259 return (BHND_NVRAM_SRC_SPROM); 260 261 /* Most other early devices require checking ChipStatus flags */ 262 if (CHIPC_QUIRK(sc, SPROM_CHECK_CHIPST)) 263 return (chipc_nvram_src_chipst(sc)); 264 265 /* 266 * Later chipset revisions standardized the NVRAM capability flags and 267 * register interfaces. 268 * 269 * We check for hardware presence in order of precedence. For example, 270 * SPROM is is always used in preference to internal OTP if found. 271 */ 272 if (CHIPC_CAP(sc, CAP_SPROM)) { 273 srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL); 274 if (srom_ctrl & CHIPC_SRC_PRESENT) 275 return (BHND_NVRAM_SRC_SPROM); 276 } 277 278 /* Check for OTP */ 279 if (CHIPC_CAP(sc, CAP_OTP_SIZE)) 280 return (BHND_NVRAM_SRC_OTP); 281 282 /* 283 * Finally, Northstar chipsets (and possibly other chipsets?) support 284 * external NAND flash. 285 */ 286 if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH)) 287 return (BHND_NVRAM_SRC_NFLASH); 288 289 /* No NVRAM hardware capability declared */ 290 return (BHND_NVRAM_SRC_NONE); 291 } 292 293 static device_method_t chipc_methods[] = { 294 /* Device interface */ 295 DEVMETHOD(device_probe, chipc_probe), 296 DEVMETHOD(device_attach, chipc_attach), 297 DEVMETHOD(device_detach, chipc_detach), 298 DEVMETHOD(device_suspend, chipc_suspend), 299 DEVMETHOD(device_resume, chipc_resume), 300 301 /* ChipCommon interface */ 302 DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src), 303 304 DEVMETHOD_END 305 }; 306 307 DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc)); 308 DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0); 309 MODULE_VERSION(bhnd_chipc, 1); 310