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 /* Supported device identifiers */ 66 static const struct chipc_device { 67 uint16_t device; 68 } chipc_devices[] = { 69 { BHND_COREID_CC }, 70 { BHND_COREID_INVALID } 71 }; 72 73 /* Device quirks table */ 74 static struct bhnd_device_quirk chipc_quirks[] = { 75 BHND_QUIRK_HWREV_RANGE (0, 21, CHIPC_QUIRK_ALWAYS_HAS_SPROM), 76 BHND_QUIRK_HWREV_EQ (22, CHIPC_QUIRK_SPROM_CHECK_CST_R22), 77 BHND_QUIRK_HWREV_RANGE (23, 31, CHIPC_QUIRK_SPROM_CHECK_CST_R23), 78 BHND_QUIRK_HWREV_GTE (35, CHIPC_QUIRK_SUPPORTS_NFLASH), 79 BHND_QUIRK_HWREV_END 80 }; 81 82 /* quirk and capability flag convenience macros */ 83 #define CHIPC_QUIRK(_sc, _name) \ 84 ((_sc)->quirks & CHIPC_QUIRK_ ## _name) 85 86 #define CHIPC_CAP(_sc, _name) \ 87 ((_sc)->caps & CHIPC_ ## _name) 88 89 #define CHIPC_ASSERT_QUIRK(_sc, name) \ 90 KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) 91 92 #define CHIPC_ASSERT_CAP(_sc, name) \ 93 KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set")) 94 95 static int 96 chipc_probe(device_t dev) 97 { 98 const struct chipc_device *id; 99 100 for (id = chipc_devices; id->device != BHND_COREID_INVALID; id++) 101 { 102 if (bhnd_get_vendor(dev) == BHND_MFGID_BCM && 103 bhnd_get_device(dev) == id->device) 104 { 105 bhnd_set_generic_core_desc(dev); 106 return (BUS_PROBE_DEFAULT); 107 } 108 } 109 110 return (ENXIO); 111 } 112 113 static int 114 chipc_attach(device_t dev) 115 { 116 struct bhnd_device_quirk *dq; 117 struct chipc_softc *sc; 118 bhnd_addr_t enum_addr; 119 uint32_t ccid_reg; 120 uint8_t chip_type; 121 int error; 122 123 sc = device_get_softc(dev); 124 sc->dev = dev; 125 126 /* Allocate bus resources */ 127 memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec)); 128 if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res))) 129 return (error); 130 131 sc->core = sc->res[0]; 132 133 /* Fetch our chipset identification data */ 134 ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID); 135 chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS); 136 137 switch (chip_type) { 138 case BHND_CHIPTYPE_SIBA: 139 /* enumeration space starts at the ChipCommon register base. */ 140 enum_addr = rman_get_start(sc->core->res); 141 break; 142 case BHND_CHIPTYPE_BCMA: 143 case BHND_CHIPTYPE_BCMA_ALT: 144 enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR); 145 break; 146 default: 147 device_printf(dev, "unsupported chip type %hhu\n", chip_type); 148 error = ENODEV; 149 goto cleanup; 150 } 151 152 sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr); 153 154 /* Fetch capability and status register values */ 155 sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES); 156 sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST); 157 158 /* Populate the set of applicable quirk flags */ 159 sc->quirks = 0; 160 for (dq = chipc_quirks; dq->quirks != 0; dq++) { 161 if (bhnd_hwrev_matches(bhnd_get_hwrev(dev), &dq->hwrev)) 162 sc->quirks |= dq->quirks; 163 }; 164 165 // TODO 166 switch (bhnd_chipc_nvram_src(dev)) { 167 case BHND_NVRAM_SRC_CIS: 168 device_printf(dev, "NVRAM source: CIS\n"); 169 break; 170 case BHND_NVRAM_SRC_SPROM: 171 device_printf(dev, "NVRAM source: SPROM\n"); 172 break; 173 case BHND_NVRAM_SRC_OTP: 174 device_printf(dev, "NVRAM source: OTP\n"); 175 break; 176 case BHND_NVRAM_SRC_NFLASH: 177 device_printf(dev, "NVRAM source: NFLASH\n"); 178 break; 179 case BHND_NVRAM_SRC_NONE: 180 device_printf(dev, "NVRAM source: NONE\n"); 181 break; 182 } 183 184 return (0); 185 186 cleanup: 187 bhnd_release_resources(dev, sc->rspec, sc->res); 188 return (error); 189 } 190 191 static int 192 chipc_detach(device_t dev) 193 { 194 struct chipc_softc *sc; 195 196 sc = device_get_softc(dev); 197 bhnd_release_resources(dev, sc->rspec, sc->res); 198 199 return (0); 200 } 201 202 static int 203 chipc_suspend(device_t dev) 204 { 205 return (0); 206 } 207 208 static int 209 chipc_resume(device_t dev) 210 { 211 return (0); 212 } 213 214 /** 215 * Use device-specific ChipStatus flags to determine the preferred NVRAM 216 * data source. 217 */ 218 static bhnd_nvram_src_t 219 chipc_nvram_src_chipst(struct chipc_softc *sc) 220 { 221 uint8_t nvram_sel; 222 223 CHIPC_ASSERT_QUIRK(sc, SPROM_CHECK_CHIPST); 224 225 if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R22)) { 226 // TODO: On these devices, the official driver code always 227 // assumes SPROM availability if CHIPC_CST_OTP_SEL is not 228 // set; we must review against the actual behavior of our 229 // BCM4312 hardware 230 nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R22); 231 } else if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R23)) { 232 nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R23); 233 } else { 234 panic("invalid CST OTP/SPROM chipc quirk flags"); 235 } 236 device_printf(sc->dev, "querying chipst for 0x%x, 0x%x\n", sc->ccid.chip_id, sc->cst); 237 238 switch (nvram_sel) { 239 case CHIPC_CST_DEFCIS_SEL: 240 return (BHND_NVRAM_SRC_CIS); 241 242 case CHIPC_CST_SPROM_SEL: 243 case CHIPC_CST_OTP_PWRDN: 244 return (BHND_NVRAM_SRC_SPROM); 245 246 case CHIPC_CST_OTP_SEL: 247 return (BHND_NVRAM_SRC_OTP); 248 249 default: 250 device_printf(sc->dev, "unrecognized OTP/SPROM type 0x%hhx", 251 nvram_sel); 252 return (BHND_NVRAM_SRC_NONE); 253 } 254 } 255 256 /** 257 * Determine the preferred NVRAM data source. 258 */ 259 static bhnd_nvram_src_t 260 chipc_nvram_src(device_t dev) 261 { 262 struct chipc_softc *sc; 263 uint32_t srom_ctrl; 264 265 sc = device_get_softc(dev); 266 267 /* Very early devices always included a SPROM */ 268 if (CHIPC_QUIRK(sc, ALWAYS_HAS_SPROM)) 269 return (BHND_NVRAM_SRC_SPROM); 270 271 /* Most other early devices require checking ChipStatus flags */ 272 if (CHIPC_QUIRK(sc, SPROM_CHECK_CHIPST)) 273 return (chipc_nvram_src_chipst(sc)); 274 275 /* 276 * Later chipset revisions standardized the NVRAM capability flags and 277 * register interfaces. 278 * 279 * We check for hardware presence in order of precedence. For example, 280 * SPROM is is always used in preference to internal OTP if found. 281 */ 282 if (CHIPC_CAP(sc, CAP_SPROM)) { 283 srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL); 284 if (srom_ctrl & CHIPC_SRC_PRESENT) 285 return (BHND_NVRAM_SRC_SPROM); 286 } 287 288 /* Check for OTP */ 289 if (CHIPC_CAP(sc, CAP_OTP_SIZE)) 290 return (BHND_NVRAM_SRC_OTP); 291 292 /* 293 * Finally, Northstar chipsets (and possibly other chipsets?) support 294 * external NAND flash. 295 */ 296 if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH)) 297 return (BHND_NVRAM_SRC_NFLASH); 298 299 /* No NVRAM hardware capability declared */ 300 return (BHND_NVRAM_SRC_NONE); 301 } 302 303 static device_method_t chipc_methods[] = { 304 /* Device interface */ 305 DEVMETHOD(device_probe, chipc_probe), 306 DEVMETHOD(device_attach, chipc_attach), 307 DEVMETHOD(device_detach, chipc_detach), 308 DEVMETHOD(device_suspend, chipc_suspend), 309 DEVMETHOD(device_resume, chipc_resume), 310 311 /* ChipCommon interface */ 312 DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src), 313 314 DEVMETHOD_END 315 }; 316 317 DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc)); 318 DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0); 319 MODULE_VERSION(bhnd_chipc, 1); 320