xref: /freebsd/sys/dev/bhnd/cores/chipc/chipc.c (revision 30b72b6871140f0b29c64d41fc85c4c1d4d4b3f4)
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